From 5375bb5b86e266157ceceef08c367da711b8144e Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sat, 1 Jun 2013 01:04:32 +0200 Subject: Cleanup, WIP, needs a NuttX checkout to Firmware/NuttX now --- nuttx/drivers/Kconfig | 445 --- nuttx/drivers/Makefile | 122 - nuttx/drivers/README.txt | 145 - nuttx/drivers/analog/Kconfig | 77 - nuttx/drivers/analog/Make.defs | 87 - nuttx/drivers/analog/ad5410.c | 205 -- nuttx/drivers/analog/adc.c | 434 --- nuttx/drivers/analog/ads1255.c | 335 -- nuttx/drivers/analog/dac.c | 499 --- nuttx/drivers/analog/pga11x.c | 793 ----- nuttx/drivers/bch/Kconfig | 4 - nuttx/drivers/bch/Make.defs | 52 - nuttx/drivers/bch/bch_internal.h | 102 - nuttx/drivers/bch/bchdev_driver.c | 255 -- nuttx/drivers/bch/bchdev_register.c | 104 - nuttx/drivers/bch/bchdev_unregister.c | 160 - nuttx/drivers/bch/bchlib_cache.c | 133 - nuttx/drivers/bch/bchlib_read.c | 203 -- nuttx/drivers/bch/bchlib_sem.c | 84 - nuttx/drivers/bch/bchlib_setup.c | 159 - nuttx/drivers/bch/bchlib_teardown.c | 113 - nuttx/drivers/bch/bchlib_write.c | 216 -- nuttx/drivers/can.c | 845 ------ nuttx/drivers/dev_null.c | 135 - nuttx/drivers/dev_zero.c | 135 - nuttx/drivers/input/Kconfig | 228 -- nuttx/drivers/input/Make.defs | 76 - nuttx/drivers/input/ads7843e.c | 1283 -------- nuttx/drivers/input/ads7843e.h | 179 -- nuttx/drivers/input/max11802.c | 1313 -------- nuttx/drivers/input/max11802.h | 167 - nuttx/drivers/input/stmpe811.h | 245 -- nuttx/drivers/input/stmpe811_adc.c | 266 -- nuttx/drivers/input/stmpe811_base.c | 546 ---- nuttx/drivers/input/stmpe811_gpio.c | 454 --- nuttx/drivers/input/stmpe811_temp.c | 174 -- nuttx/drivers/input/stmpe811_tsc.c | 1144 ------- nuttx/drivers/input/tsc2007.c | 1336 -------- nuttx/drivers/input/tsc2007.h | 120 - nuttx/drivers/lcd/Kconfig | 330 -- nuttx/drivers/lcd/Make.defs | 76 - nuttx/drivers/lcd/README.txt | 189 -- nuttx/drivers/lcd/mio283qt2.c | 1014 ------- nuttx/drivers/lcd/nokia6100.c | 1230 -------- nuttx/drivers/lcd/p14201.c | 1246 -------- nuttx/drivers/lcd/pcf8833.h | 152 - nuttx/drivers/lcd/s1d15g10.h | 141 - nuttx/drivers/lcd/sd1329.h | 527 ---- nuttx/drivers/lcd/skeleton.c | 401 --- nuttx/drivers/lcd/ssd1289.c | 1380 --------- nuttx/drivers/lcd/ssd1289.h | 425 --- nuttx/drivers/lcd/ssd1305.h | 211 -- nuttx/drivers/lcd/ug-2864ambag01.c | 1161 ------- nuttx/drivers/lcd/ug-2864hsweg01.c | 1218 -------- nuttx/drivers/lcd/ug-9664hswag01.c | 1046 ------- nuttx/drivers/loop.c | 509 ---- nuttx/drivers/mmcsd/Kconfig | 79 - nuttx/drivers/mmcsd/Make.defs | 56 - nuttx/drivers/mmcsd/mmcsd_csd.h | 424 --- nuttx/drivers/mmcsd/mmcsd_debug.c | 183 -- nuttx/drivers/mmcsd/mmcsd_internal.h | 105 - nuttx/drivers/mmcsd/mmcsd_sdio.c | 3186 -------------------- nuttx/drivers/mmcsd/mmcsd_sdio.h | 339 --- nuttx/drivers/mmcsd/mmcsd_spi.c | 1889 ------------ nuttx/drivers/mmcsd/mmcsd_spi.h | 187 -- nuttx/drivers/mtd/Kconfig | 133 - nuttx/drivers/mtd/Make.defs | 65 - nuttx/drivers/mtd/at24xx.c | 429 --- nuttx/drivers/mtd/at25.c | 710 ----- nuttx/drivers/mtd/at45db.c | 899 ------ nuttx/drivers/mtd/flash_eraseall.c | 117 - nuttx/drivers/mtd/ftl.c | 601 ---- nuttx/drivers/mtd/m25px.c | 798 ----- nuttx/drivers/mtd/rammtd.c | 417 --- nuttx/drivers/mtd/ramtron.c | 686 ----- nuttx/drivers/mtd/skeleton.c | 275 -- nuttx/drivers/mtd/sst25.c | 1250 -------- nuttx/drivers/mtd/w25.c | 1179 -------- nuttx/drivers/net/Kconfig | 95 - nuttx/drivers/net/Make.defs | 71 - nuttx/drivers/net/cs89x0.c | 959 ------ nuttx/drivers/net/cs89x0.h | 326 -- nuttx/drivers/net/dm90x0.c | 1815 ----------- nuttx/drivers/net/e1000.c | 1042 ------- nuttx/drivers/net/e1000.h | 121 - nuttx/drivers/net/enc28j60.c | 2624 ---------------- nuttx/drivers/net/enc28j60.h | 477 --- nuttx/drivers/net/skeleton.c | 692 ----- nuttx/drivers/net/slip.c | 1017 ------- nuttx/drivers/net/vnet.c | 672 ----- nuttx/drivers/pipes/Kconfig | 4 - nuttx/drivers/pipes/Make.defs | 46 - nuttx/drivers/pipes/fifo.c | 139 - nuttx/drivers/pipes/pipe.c | 286 -- nuttx/drivers/pipes/pipe_common.c | 682 ----- nuttx/drivers/pipes/pipe_common.h | 139 - nuttx/drivers/power/Kconfig | 23 - nuttx/drivers/power/Make.defs | 84 - nuttx/drivers/power/battery.c | 254 -- nuttx/drivers/power/max1704x.c | 564 ---- nuttx/drivers/power/pm_activity.c | 166 - nuttx/drivers/power/pm_changestate.c | 227 -- nuttx/drivers/power/pm_checkstate.c | 161 - nuttx/drivers/power/pm_initialize.c | 112 - nuttx/drivers/power/pm_internal.h | 210 -- nuttx/drivers/power/pm_register.c | 112 - nuttx/drivers/power/pm_update.c | 334 -- nuttx/drivers/pwm.c | 676 ----- nuttx/drivers/ramdisk.c | 342 --- nuttx/drivers/rwbuffer.c | 682 ----- nuttx/drivers/sensors/Kconfig | 33 - nuttx/drivers/sensors/Make.defs | 60 - nuttx/drivers/sensors/lis331dl.c | 320 -- nuttx/drivers/sensors/lm75.c | 537 ---- nuttx/drivers/sensors/qencoder.c | 402 --- nuttx/drivers/sercomm/Kconfig | 4 - nuttx/drivers/sercomm/Make.defs | 55 - nuttx/drivers/sercomm/README.txt | 19 - nuttx/drivers/sercomm/console.c | 182 -- nuttx/drivers/sercomm/loadwriter.py | 19 - nuttx/drivers/sercomm/uart.c | 469 --- nuttx/drivers/sercomm/uart.h | 32 - nuttx/drivers/serial/Kconfig | 1054 ------- nuttx/drivers/serial/Make.defs | 50 - nuttx/drivers/serial/lowconsole.c | 132 - nuttx/drivers/serial/serial.c | 1377 --------- nuttx/drivers/serial/serialirq.c | 186 -- nuttx/drivers/serial/uart_16550.c | 1164 ------- nuttx/drivers/syslog/Kconfig | 73 - nuttx/drivers/syslog/Make.defs | 68 - nuttx/drivers/syslog/README.txt | 64 - nuttx/drivers/syslog/ramlog.c | 770 ----- nuttx/drivers/usbdev/Kconfig | 513 ---- nuttx/drivers/usbdev/Make.defs | 63 - nuttx/drivers/usbdev/cdcacm.c | 2329 -------------- nuttx/drivers/usbdev/cdcacm.h | 350 --- nuttx/drivers/usbdev/cdcacm_desc.c | 613 ---- nuttx/drivers/usbdev/composite.c | 933 ------ nuttx/drivers/usbdev/composite.h | 326 -- nuttx/drivers/usbdev/composite_desc.c | 291 -- nuttx/drivers/usbdev/pl2303.c | 2355 --------------- nuttx/drivers/usbdev/usbdev_trace.c | 233 -- nuttx/drivers/usbdev/usbdev_trprintf.c | 253 -- nuttx/drivers/usbdev/usbmsc.c | 1778 ----------- nuttx/drivers/usbdev/usbmsc.h | 694 ----- nuttx/drivers/usbdev/usbmsc_desc.c | 421 --- nuttx/drivers/usbdev/usbmsc_scsi.c | 2667 ---------------- nuttx/drivers/usbhost/Kconfig | 114 - nuttx/drivers/usbhost/Make.defs | 57 - nuttx/drivers/usbhost/hid_parser.c | 529 ---- nuttx/drivers/usbhost/usbhost_enumerate.c | 518 ---- nuttx/drivers/usbhost/usbhost_findclass.c | 199 -- nuttx/drivers/usbhost/usbhost_hidkbd.c | 2353 --------------- nuttx/drivers/usbhost/usbhost_registerclass.c | 117 - nuttx/drivers/usbhost/usbhost_registry.c | 80 - nuttx/drivers/usbhost/usbhost_registry.h | 87 - nuttx/drivers/usbhost/usbhost_skeleton.c | 1060 ------- nuttx/drivers/usbhost/usbhost_storage.c | 2244 -------------- nuttx/drivers/watchdog.c | 575 ---- nuttx/drivers/wireless/Kconfig | 4 - nuttx/drivers/wireless/Make.defs | 47 - .../wireless/cc1101/ISM1_868MHzGFSK100kbps.c | 113 - .../wireless/cc1101/ISM2_905MHzGFSK250kbps.c | 111 - nuttx/drivers/wireless/cc1101/Kconfig | 4 - nuttx/drivers/wireless/cc1101/cc1101.c | 812 ----- 165 files changed, 83703 deletions(-) delete mode 100644 nuttx/drivers/Kconfig delete mode 100644 nuttx/drivers/Makefile delete mode 100644 nuttx/drivers/README.txt delete mode 100644 nuttx/drivers/analog/Kconfig delete mode 100644 nuttx/drivers/analog/Make.defs delete mode 100644 nuttx/drivers/analog/ad5410.c delete mode 100644 nuttx/drivers/analog/adc.c delete mode 100644 nuttx/drivers/analog/ads1255.c delete mode 100644 nuttx/drivers/analog/dac.c delete mode 100644 nuttx/drivers/analog/pga11x.c delete mode 100644 nuttx/drivers/bch/Kconfig delete mode 100644 nuttx/drivers/bch/Make.defs delete mode 100644 nuttx/drivers/bch/bch_internal.h delete mode 100644 nuttx/drivers/bch/bchdev_driver.c delete mode 100644 nuttx/drivers/bch/bchdev_register.c delete mode 100644 nuttx/drivers/bch/bchdev_unregister.c delete mode 100644 nuttx/drivers/bch/bchlib_cache.c delete mode 100644 nuttx/drivers/bch/bchlib_read.c delete mode 100644 nuttx/drivers/bch/bchlib_sem.c delete mode 100644 nuttx/drivers/bch/bchlib_setup.c delete mode 100644 nuttx/drivers/bch/bchlib_teardown.c delete mode 100644 nuttx/drivers/bch/bchlib_write.c delete mode 100644 nuttx/drivers/can.c delete mode 100644 nuttx/drivers/dev_null.c delete mode 100644 nuttx/drivers/dev_zero.c delete mode 100644 nuttx/drivers/input/Kconfig delete mode 100644 nuttx/drivers/input/Make.defs delete mode 100644 nuttx/drivers/input/ads7843e.c delete mode 100644 nuttx/drivers/input/ads7843e.h delete mode 100644 nuttx/drivers/input/max11802.c delete mode 100644 nuttx/drivers/input/max11802.h delete mode 100644 nuttx/drivers/input/stmpe811.h delete mode 100644 nuttx/drivers/input/stmpe811_adc.c delete mode 100644 nuttx/drivers/input/stmpe811_base.c delete mode 100644 nuttx/drivers/input/stmpe811_gpio.c delete mode 100644 nuttx/drivers/input/stmpe811_temp.c delete mode 100644 nuttx/drivers/input/stmpe811_tsc.c delete mode 100644 nuttx/drivers/input/tsc2007.c delete mode 100644 nuttx/drivers/input/tsc2007.h delete mode 100644 nuttx/drivers/lcd/Kconfig delete mode 100644 nuttx/drivers/lcd/Make.defs delete mode 100644 nuttx/drivers/lcd/README.txt delete mode 100644 nuttx/drivers/lcd/mio283qt2.c delete mode 100644 nuttx/drivers/lcd/nokia6100.c delete mode 100644 nuttx/drivers/lcd/p14201.c delete mode 100644 nuttx/drivers/lcd/pcf8833.h delete mode 100644 nuttx/drivers/lcd/s1d15g10.h delete mode 100644 nuttx/drivers/lcd/sd1329.h delete mode 100644 nuttx/drivers/lcd/skeleton.c delete mode 100644 nuttx/drivers/lcd/ssd1289.c delete mode 100644 nuttx/drivers/lcd/ssd1289.h delete mode 100644 nuttx/drivers/lcd/ssd1305.h delete mode 100644 nuttx/drivers/lcd/ug-2864ambag01.c delete mode 100644 nuttx/drivers/lcd/ug-2864hsweg01.c delete mode 100644 nuttx/drivers/lcd/ug-9664hswag01.c delete mode 100644 nuttx/drivers/loop.c delete mode 100644 nuttx/drivers/mmcsd/Kconfig delete mode 100644 nuttx/drivers/mmcsd/Make.defs delete mode 100644 nuttx/drivers/mmcsd/mmcsd_csd.h delete mode 100644 nuttx/drivers/mmcsd/mmcsd_debug.c delete mode 100644 nuttx/drivers/mmcsd/mmcsd_internal.h delete mode 100644 nuttx/drivers/mmcsd/mmcsd_sdio.c delete mode 100644 nuttx/drivers/mmcsd/mmcsd_sdio.h delete mode 100644 nuttx/drivers/mmcsd/mmcsd_spi.c delete mode 100644 nuttx/drivers/mmcsd/mmcsd_spi.h delete mode 100644 nuttx/drivers/mtd/Kconfig delete mode 100644 nuttx/drivers/mtd/Make.defs delete mode 100644 nuttx/drivers/mtd/at24xx.c delete mode 100644 nuttx/drivers/mtd/at25.c delete mode 100644 nuttx/drivers/mtd/at45db.c delete mode 100644 nuttx/drivers/mtd/flash_eraseall.c delete mode 100644 nuttx/drivers/mtd/ftl.c delete mode 100644 nuttx/drivers/mtd/m25px.c delete mode 100644 nuttx/drivers/mtd/rammtd.c delete mode 100644 nuttx/drivers/mtd/ramtron.c delete mode 100644 nuttx/drivers/mtd/skeleton.c delete mode 100644 nuttx/drivers/mtd/sst25.c delete mode 100644 nuttx/drivers/mtd/w25.c delete mode 100644 nuttx/drivers/net/Kconfig delete mode 100644 nuttx/drivers/net/Make.defs delete mode 100644 nuttx/drivers/net/cs89x0.c delete mode 100644 nuttx/drivers/net/cs89x0.h delete mode 100644 nuttx/drivers/net/dm90x0.c delete mode 100644 nuttx/drivers/net/e1000.c delete mode 100644 nuttx/drivers/net/e1000.h delete mode 100644 nuttx/drivers/net/enc28j60.c delete mode 100644 nuttx/drivers/net/enc28j60.h delete mode 100644 nuttx/drivers/net/skeleton.c delete mode 100644 nuttx/drivers/net/slip.c delete mode 100644 nuttx/drivers/net/vnet.c delete mode 100644 nuttx/drivers/pipes/Kconfig delete mode 100644 nuttx/drivers/pipes/Make.defs delete mode 100644 nuttx/drivers/pipes/fifo.c delete mode 100644 nuttx/drivers/pipes/pipe.c delete mode 100644 nuttx/drivers/pipes/pipe_common.c delete mode 100644 nuttx/drivers/pipes/pipe_common.h delete mode 100644 nuttx/drivers/power/Kconfig delete mode 100644 nuttx/drivers/power/Make.defs delete mode 100644 nuttx/drivers/power/battery.c delete mode 100644 nuttx/drivers/power/max1704x.c delete mode 100644 nuttx/drivers/power/pm_activity.c delete mode 100644 nuttx/drivers/power/pm_changestate.c delete mode 100644 nuttx/drivers/power/pm_checkstate.c delete mode 100644 nuttx/drivers/power/pm_initialize.c delete mode 100644 nuttx/drivers/power/pm_internal.h delete mode 100644 nuttx/drivers/power/pm_register.c delete mode 100644 nuttx/drivers/power/pm_update.c delete mode 100644 nuttx/drivers/pwm.c delete mode 100644 nuttx/drivers/ramdisk.c delete mode 100644 nuttx/drivers/rwbuffer.c delete mode 100644 nuttx/drivers/sensors/Kconfig delete mode 100644 nuttx/drivers/sensors/Make.defs delete mode 100644 nuttx/drivers/sensors/lis331dl.c delete mode 100644 nuttx/drivers/sensors/lm75.c delete mode 100644 nuttx/drivers/sensors/qencoder.c delete mode 100644 nuttx/drivers/sercomm/Kconfig delete mode 100644 nuttx/drivers/sercomm/Make.defs delete mode 100644 nuttx/drivers/sercomm/README.txt delete mode 100644 nuttx/drivers/sercomm/console.c delete mode 100644 nuttx/drivers/sercomm/loadwriter.py delete mode 100644 nuttx/drivers/sercomm/uart.c delete mode 100644 nuttx/drivers/sercomm/uart.h delete mode 100644 nuttx/drivers/serial/Kconfig delete mode 100644 nuttx/drivers/serial/Make.defs delete mode 100644 nuttx/drivers/serial/lowconsole.c delete mode 100644 nuttx/drivers/serial/serial.c delete mode 100644 nuttx/drivers/serial/serialirq.c delete mode 100644 nuttx/drivers/serial/uart_16550.c delete mode 100644 nuttx/drivers/syslog/Kconfig delete mode 100644 nuttx/drivers/syslog/Make.defs delete mode 100644 nuttx/drivers/syslog/README.txt delete mode 100644 nuttx/drivers/syslog/ramlog.c delete mode 100644 nuttx/drivers/usbdev/Kconfig delete mode 100644 nuttx/drivers/usbdev/Make.defs delete mode 100644 nuttx/drivers/usbdev/cdcacm.c delete mode 100644 nuttx/drivers/usbdev/cdcacm.h delete mode 100644 nuttx/drivers/usbdev/cdcacm_desc.c delete mode 100644 nuttx/drivers/usbdev/composite.c delete mode 100644 nuttx/drivers/usbdev/composite.h delete mode 100644 nuttx/drivers/usbdev/composite_desc.c delete mode 100644 nuttx/drivers/usbdev/pl2303.c delete mode 100644 nuttx/drivers/usbdev/usbdev_trace.c delete mode 100644 nuttx/drivers/usbdev/usbdev_trprintf.c delete mode 100644 nuttx/drivers/usbdev/usbmsc.c delete mode 100644 nuttx/drivers/usbdev/usbmsc.h delete mode 100644 nuttx/drivers/usbdev/usbmsc_desc.c delete mode 100644 nuttx/drivers/usbdev/usbmsc_scsi.c delete mode 100644 nuttx/drivers/usbhost/Kconfig delete mode 100644 nuttx/drivers/usbhost/Make.defs delete mode 100644 nuttx/drivers/usbhost/hid_parser.c delete mode 100644 nuttx/drivers/usbhost/usbhost_enumerate.c delete mode 100644 nuttx/drivers/usbhost/usbhost_findclass.c delete mode 100644 nuttx/drivers/usbhost/usbhost_hidkbd.c delete mode 100644 nuttx/drivers/usbhost/usbhost_registerclass.c delete mode 100644 nuttx/drivers/usbhost/usbhost_registry.c delete mode 100644 nuttx/drivers/usbhost/usbhost_registry.h delete mode 100644 nuttx/drivers/usbhost/usbhost_skeleton.c delete mode 100644 nuttx/drivers/usbhost/usbhost_storage.c delete mode 100644 nuttx/drivers/watchdog.c delete mode 100644 nuttx/drivers/wireless/Kconfig delete mode 100644 nuttx/drivers/wireless/Make.defs delete mode 100644 nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c delete mode 100644 nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c delete mode 100644 nuttx/drivers/wireless/cc1101/Kconfig delete mode 100644 nuttx/drivers/wireless/cc1101/cc1101.c (limited to 'nuttx/drivers') diff --git a/nuttx/drivers/Kconfig b/nuttx/drivers/Kconfig deleted file mode 100644 index f3d2c871a..000000000 --- a/nuttx/drivers/Kconfig +++ /dev/null @@ -1,445 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config DISABLE_POLL - bool "Disable driver poll interfaces" - default n - ---help--- - The sizes of drivers can be reduced if the poll() method is not - supported. If you do not use poll() or select(), then you can - select DISABLE_POLL to reduce the code footprint by a small amount. - -config DEV_NULL - bool "Enable /dev/null" - default y - -config DEV_ZERO - bool "Enable /dev/zero" - default n - -config ARCH_HAVE_RNG - bool - -config DEV_RANDOM - bool "Enable /dev/random" - default n - depends on ARCH_HAVE_RNG - -config LOOP - bool "Enable loop device" - default n - ---help--- - Supports the standard loop device that can be used to export a - file (or character device) as a block device. See losetup() and - loteardown() in include/nuttx/fs/fs.h. - -config RAMDISK - bool "RAM Disk Support" - default n - ---help--- - Can be used to set up a block of memory or (read-only) FLASH as - a block driver that can be mounted as a files system. See - include/nuttx/ramdisk.h. - -menuconfig CAN - bool "CAN Driver Support" - default n - ---help--- - This selection enables building of the "upper-half" CAN driver. - See include/nuttx/can.h for further CAN driver information. - -if CAN -config CAN_EXTID - bool "CAN extended IDs" - default n - ---help--- - Enables support for the 29-bit extended ID. Default Standard 11-bit - IDs. - -config CAN_FIFOSIZE - int "CAN driver I/O buffer size" - default 8 - ---help--- - The size of the circular buffer of CAN messages. Default: 8 - -config CAN_NPENDINGRTR - int "Number of pending RTRs" - default 4 - ---help--- - The size of the list of pending RTR requests. Default: 4 - -config CAN_LOOPBACK - bool "CAN extended IDs" - default n - ---help--- - A CAN driver may or may not support a loopback mode for testing. If the - driver does support loopback mode, the setting will enable it. (If the - driver does not, this setting will have no effect). - -endif - -menuconfig PWM - bool "PWM Driver Support" - default n - ---help--- - This selection enables building of the "upper-half" PWM driver. - See include/nuttx/pwm.h for further PWM driver information. - -if PWM -config PWM_PULSECOUNT - bool "PWM Pulse Count Support" - default n - ---help--- - Some hardware will support generation of a fixed number of pulses. - This might be used, for example to support a stepper motor. If the - hardware will support a fixed pulse count, then this configuration - should be set to enable the capability. - -endif - -menuconfig I2C - bool "I2C Driver Support" - default n - ---help--- - This selection enables building of the "upper-half" I2C driver. - See include/nuttx/i2c.h for further I2C driver information. - -config I2C_SLAVE - bool "I2C Slave" - default n - depends on I2C - -config I2C_TRANSFER - bool "Support the I2C transfer() method" - default n - depends on I2C - -config I2C_WRITEREAD - bool "Support the I2C writeread() method" - default n - depends on I2C - -config I2C_POLLED - bool "Polled I2C (no interrupts)" - default n - depends on I2C - -config I2C_TRACE - bool "Enable I2C trace debug" - default n - depends on I2C - -config I2C_NTRACE - bool "Enable I2C trace debug" - default n - depends on I2C_TRACE - -config ARCH_HAVE_I2CRESET - bool - -config I2C_RESET - bool "Support up_i2creset" - default n - depends on I2C && ARCH_HAVE_I2CRESET - -menuconfig SPI - bool "SPI Driver Support" - default n - ---help--- - This selection enables selection of common SPI options. This option - should be enabled by all platforms that support SPI interfaces. - See include/nuttx/spi.h for further SPI driver information. - -if SPI -config SPI_OWNBUS - bool "SPI single device" - default n - ---help--- - Set if there is only one active device on the SPI bus. No locking or - SPI configuration will be performed. It is not necessary for clients to - lock, re-configure, etc.. - -config SPI_EXCHANGE - bool "SPI exchange" - default y - ---help--- - Driver supports a single exchange method (vs a recvblock() and - sndblock() methods). - -config SPI_CMDDATA - bool "SPI CMD/DATA" - default n - ---help--- - Devices on the SPI bus require out-of-band support to distinguish - command transfers from data transfers. Such devices will often support - either 9-bit SPI (yech) or 8-bit SPI and a GPIO output that selects - between command and data. - -endif - -menuconfig RTC - bool "RTC Driver Support" - default n - ---help--- - This selection enables configuration of a real time clock (RTCdriver. - See include/nuttx/rtc.h for further watchdog timer driver information. - Most RTC drivers are MCU specific and may require other specific - settings. - -config RTC_DATETIME - bool "Date/Time RTC Support" - default n - depends on RTC - ---help--- - There are two general types of RTC: (1) A simple battery backed - counter that keeps the time when power is down, and (2) a full - date / time RTC the provides the date and time information, often in - BCD format. If RTC_DATETIME is selected, it specifies this second kind - of RTC. In this case, the RTC is used to "seed" the normal NuttX timer - and the NuttX system timer provides for higher resolution time. - -config RTC_HIRES - bool "Hi-Res RTC Support" - default n - depends on RTC && !RTC_DATETIME - ---help--- - If RTC_DATETIME not selected, then the simple, battery backed counter - is used. There are two different implementations of such simple - counters based on the time resolution of the counter: The typical RTC - keeps time to resolution of 1 second, usually supporting a 32-bit - time_t value. In this case, the RTC is used to "seed" the normal NuttX - timer and the NuttX timer provides for higherresoution time. - - If RTC_HIRES is enabled in the NuttX configuration, then the RTC - provides higher resolution time and completely replaces the system - timer for purpose of date and time. - -config RTC_FREQUENCY - int "Hi-Res RTC frequency" - default 1 - depends on RTC && !RTC_DATETIME && RTC_HIRES - ---help--- - If RTC_HIRES is defined, then the frequency of the high resolution RTC - must be provided. If RTC_HIRES is not defined, RTC_FREQUENCY is - assumed to be one Hz. - -config RTC_ALARM - bool "RTC Alarm Support" - default n - depends on RTC - ---help--- - Enable if the RTC hardware supports setting of an alarm. A callback - function will be executed when the alarm goes off. - -menuconfig WATCHDOG - bool "Watchdog Timer Support" - default n - ---help--- - This selection enables building of the "upper-half" watchdog timer - driver. See include/nuttx/watchdog.h for further watchdog timer driver - information. - -if WATCHDOG -endif - -menuconfig ANALOG - bool "Analog Device(ADC/DAC) Support" - default n - ---help--- - This directory holds implementations of analog device drivers. - This includes drivers for Analog to Digital Conversion (ADC) as - well as drivers for Digital to Analog Conversion (DAC). - See include/nuttx/analog/*.h for registration information. - -if ANALOG -source drivers/analog/Kconfig -endif - -menuconfig BCH - bool "Block-to-Character (BCH) Support" - default n - ---help--- - Contains logic that may be used to convert a block driver into - a character driver. This is the complementary conversion as that - performed by loop.c. See include/nuttx/fs/fs.h for registration - information. - -if BCH -source drivers/bch/Kconfig -endif - -menuconfig INPUT - bool "Input Device Support" - default n - ---help--- - This directory holds implementations of input device drivers. - This includes such things as touchscreen and keypad drivers. - See include/nuttx/input/*.h for registration information. - -if INPUT -source drivers/input/Kconfig -endif - -menuconfig LCD - bool "LCD Driver Support" - default n - select NX_LCDDRIVER - ---help--- - Drivers for parallel and serial LCD and OLED type devices. These - drivers support interfaces as defined in include/nuttx/lcd/lcd.h - - This selection is necessary to enable support for LCD drivers in - drivers/lcd as well as for board-specific LCD drivers in the configs/ - subdirectories. - -if LCD -source drivers/lcd/Kconfig -endif - -menuconfig MMCSD - bool "MMC/SD Driver Support" - default n - ---help--- - Support for MMC/SD block drivers. MMC/SD block drivers based on - SPI and SDIO/MCI interfaces are supported. See include/nuttx/mmcsd.h - and include/nuttx/sdio.h for further information. - -if MMCSD -source drivers/mmcsd/Kconfig -endif - -menuconfig MTD - bool "Memory Technology Device (MTD) Support" - default n - ---help--- - Memory Technology Device (MTD) drivers. Some simple drivers for - memory technologies like FLASH, EEPROM, NVRAM, etc. See - include/nuttx/mtd.h - - (Note: This is a simple memory interface and should not be - confused with the "real" MTD developed at infradead.org. This - logic is unrelated; I just used the name MTD because I am not - aware of any other common way to refer to this class of devices). - -if MTD -source drivers/mtd/Kconfig -endif - -menuconfig NETDEVICES - bool "Network Device Support" - default n - depends on NET - ---help--- - Network interface drivers. See also include/nuttx/net/net.h - -if NETDEVICES -source drivers/net/Kconfig -endif - -menuconfig PIPES - bool "FIFO and named pipe drivers" - default n - ---help--- - FIFO and named pipe drivers. Standard interfaces are declared - in include/unistd.h - -if PIPES -source drivers/pipes/Kconfig -endif - -config PM - bool "Power management (PM) driver interfaces" - default n - ---help--- - Power management (PM) driver interfaces. These interfaces are used - to manage power usage of a platform by monitoring driver activity - and by placing drivers into reduce power usage modes when the - drivers are not active. - -menuconfig POWER - bool "Power Management Support" - default n - ---help--- - Enable building of power-related devices (battery monitors, chargers, - etc). - -if POWER -source drivers/power/Kconfig -endif - -menuconfig SENSORS - bool "Sensor Device Support" - default n - ---help--- - Drivers for various sensors - -if SENSORS -source drivers/sensors/Kconfig -endif - -menuconfig SERCOMM_CONSOLE - bool "Osmocom-bb Sercomm Driver Support" - default n - ---help--- - Sercomm is the transport used by osmocom-bb that runs on top of serial. - See http://bb.osmocom.org/trac/wiki/nuttx-bb/run for detailed the usage - of nuttx with sercomm. - - drivers/sercomm is only built if SERCOMM_CONSOLE in the NuttX - configuration file. If you attempt to build this driver without - osmocom-bb, you will get compilation errors because of header files - that are needed from the osmocom-bb. - -if SERCOMM -source drivers/sercomm/Kconfig -endif - -menuconfig SERIAL - bool "Serial Driver Support" - default y - ---help--- - Front-end character drivers for chip-specific UARTs. This provide - some TTY-like functionality and are commonly used (but not required - for) the NuttX system console. See also include/nuttx/serial/serial.h - -if SERIAL -source drivers/serial/Kconfig -endif - -menuconfig USBDEV - bool "USB Device Driver Support" - default n - ---help--- - USB device drivers. See also include/nuttx/usb/usbdev.h - -if USBDEV -source drivers/usbdev/Kconfig -endif - -menuconfig USBHOST - bool "USB Host Driver Support" - default n - ---help--- - USB host drivers. See also include/nuttx/usb/usbhost.h - -if USBHOST -source drivers/usbhost/Kconfig -endif - -menuconfig WIRELESS - bool "Wireless Device Support" - default n - ---help--- - Drivers for various wireless devices. - -if WIRELESS -source drivers/wireless/Kconfig -endif - -comment "System Logging Device Options" - -source drivers/syslog/Kconfig - - diff --git a/nuttx/drivers/Makefile b/nuttx/drivers/Makefile deleted file mode 100644 index aaaa67bd7..000000000 --- a/nuttx/drivers/Makefile +++ /dev/null @@ -1,122 +0,0 @@ -############################################################################ -# drivers/Makefile -# -# Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - --include $(TOPDIR)/Make.defs -DELIM ?= $(strip /) - -ifeq ($(WINTOOL),y) -INCDIROPT = -w -endif - -DEPPATH = --dep-path . -ASRCS = -CSRCS = -VPATH = . - -# Include support for various drivers. Each Make.defs file will add its -# files to the source file list, add its DEPPATH info, and will add -# the appropriate paths to the VPATH variable - -include analog$(DELIM)Make.defs -include bch$(DELIM)Make.defs -include input$(DELIM)Make.defs -include lcd$(DELIM)Make.defs -include mmcsd$(DELIM)Make.defs -include mtd$(DELIM)Make.defs -include net$(DELIM)Make.defs -include pipes$(DELIM)Make.defs -include power$(DELIM)Make.defs -include sensors$(DELIM)Make.defs -include sercomm$(DELIM)Make.defs -include serial$(DELIM)Make.defs -include syslog$(DELIM)Make.defs -include usbdev$(DELIM)Make.defs -include usbhost$(DELIM)Make.defs -include wireless$(DELIM)Make.defs - -ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) - CSRCS += dev_null.c dev_zero.c loop.c - -ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) - CSRCS += ramdisk.c rwbuffer.c -endif - -ifeq ($(CONFIG_CAN),y) - CSRCS += can.c -endif - -ifeq ($(CONFIG_PWM),y) - CSRCS += pwm.c -endif - -ifeq ($(CONFIG_WATCHDOG),y) - CSRCS += watchdog.c -endif -endif - -AOBJS = $(ASRCS:.S=$(OBJEXT)) -COBJS = $(CSRCS:.c=$(OBJEXT)) - -SRCS = $(ASRCS) $(CSRCS) -OBJS = $(AOBJS) $(COBJS) - -BIN = libdrivers$(LIBEXT) - -all: $(BIN) - -$(AOBJS): %$(OBJEXT): %.S - $(call ASSEMBLE, $<, $@) - -$(COBJS): %$(OBJEXT): %.c - $(call COMPILE, $<, $@) - -$(BIN): $(OBJS) - $(call ARCHIVE, $@, $(OBJS)) - -.depend: Makefile $(SRCS) - $(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep - $(Q) touch $@ - -depend: .depend - -clean: - $(call DELFILE, $(BIN)) - $(call CLEAN) - -distclean: clean - $(call DELFILE, Make.dep) - $(call DELFILE, .depend) - --include Make.dep diff --git a/nuttx/drivers/README.txt b/nuttx/drivers/README.txt deleted file mode 100644 index e27e8c583..000000000 --- a/nuttx/drivers/README.txt +++ /dev/null @@ -1,145 +0,0 @@ -README -^^^^^^ - -This directory contains various device drivers -- both block and -character drivers as well as other more specialized drivers. - -Contents: - - Files in this directory - - Subdirectories of this directory - - Skeleton files - -Files in this directory -^^^^^^^^^^^^^^^^^^^^^^^ - -can.c - This is a CAN driver. See include/nuttx/can.h for usage information. - -dev_null.c and dev_zero.c - These files provide the standard /dev/null and /dev/zero devices. - See include/nuttx/fs/fs.h for functions that should be called if you - want to register these devices (devnull_register() and - devzero_register()). - -loop.c - Supports the standard loop device that can be used to export a - file (or character device) as a block device. See losetup() and - loteardown() in include/nuttx/fs/fs.h. - -pwm.c - Provides the "upper half" of a pulse width modulation (PWM) driver. - The "lower half" of the PWM driver is provided by device-specific - logic. See include/nuttx/pwm.h for usage information. - -ramdisk.c - Can be used to set up a block of memory or (read-only) FLASH as - a block driver that can be mounted as a files system. See - include/nuttx/ramdisk.h. - -ramlog.c - This is a driver that was intended to support debugging output, - aka syslogging, when the normal serial output is not available. - For example, if you are using a telnet or USB serial console, - the debug output will get lost. - - This driver is similar to a pipe in that it saves the debugging - output in a FIFO in RAM. It differs from a pipe in numerous - details as needed to support logging. - - This driver is built when CONFIG_RAMLOG is defined in the Nuttx - configuration. - -rwbuffer.c - A facility that can be use by any block driver in-order to add - writing buffering and read-ahead buffering. - -Subdirectories of this directory: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -analog/ - This directory holds implementations of analog device drivers. - This includes drivers for Analog to Digital Conversion (ADC) as - well as drivers for Digital to Analog Conversion (DAC). - See include/nuttx/analog/*.h for registration information. - -bch/ - Contains logic that may be used to convert a block driver into - a character driver. This is the complementary conversion as that - performed by loop.c. See include/nuttx/fs/fs.h for registration - information. - -input/ - This directory holds implementations of input device drivers. - This includes such things as touchscreen and keypad drivers. - See include/nuttx/input/*.h for registration information. - -lcd/ - Drivers for parallel and serial LCD and OLED type devices. These - drivers support interfaces as defined in include/nuttx/lcd/lcd.h - -mmcsd/ - Support for MMC/SD block drivers. MMC/SD block drivers based on - SPI and SDIO/MCI interfaces are supported. See include/nuttx/mmcsd.h - and include/nuttx/sdio.h for further information. - -mtd/ - Memory Technology Device (MTD) drivers. Some simple drivers for - memory technologies like FLASH, EEPROM, NVRAM, etc. See - include/nuttx/mtd.h - - (Note: This is a simple memory interface and should not be - confused with the "real" MTD developed at infradead.org. This - logic is unrelated; I just used the name MTD because I am not - aware of any other common way to refer to this class of devices). - -net/ - Network interface drivers. See also include/nuttx/net/net.h - -pipes/ - FIFO and named pipe drivers. Standard interfaces are declared - in include/unistd.h - -power/ - Power management (PM) driver interfaces. These interfaces are used - to manage power usage of a platform by monitoring driver activity - and by placing drivers into reduce power usage modes when the - drivers are not active. - -sensors/ - Drivers for various sensors - -sercomm/ - Sercomm is the transport used by osmocom-bb that runs on top of serial. - See http://bb.osmocom.org/trac/wiki/nuttx-bb/run for detailed the usage - of nuttx with sercomm. - - drivers/sercomm is only built if CONFIG_SERCOMM_CONSOLE in the NuttX - configuration file. If you attempt to build this driver without - osmocom-bb, you will get compilation errors because of header files - that are needed from the osmocom-bb. - -serial/ - Front-end character drivers for chip-specific UARTs. This provide - some TTY-like functionality and are commonly used (but not required for) - the NuttX system console. See also include/nuttx/serial/serial.h - -usbdev/ - USB device drivers. See also include/nuttx/usb/usbdev.h - -usbhost/ - USB host drivers. See also include/nuttx/usb/usbhost.h - -wireless/ - Drivers for various wireless devices. - -Skeleton Files -^^^^^^^^^^^^^^ - -Skeleton files a "empty" frameworks for NuttX drivers. They are provided to -give you a good starting point if you want to create a new NuttX driver. -The following skeleton files are available: - - drivers/lcd/skeleton.c -- Skeleton LCD driver - drivers/mtd/skeleton.c -- Skeleton memory technology device drivers - drivers/net/skeleton.c -- Skeleton network/Ethernet drivers - drivers/usbhost/usbhost_skeleton.c -- Skeleton USB host class driver diff --git a/nuttx/drivers/analog/Kconfig b/nuttx/drivers/analog/Kconfig deleted file mode 100644 index ebed79c78..000000000 --- a/nuttx/drivers/analog/Kconfig +++ /dev/null @@ -1,77 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config ADC - bool "Analog-to-Digital Conversion" - default n - ---help--- - Select to enable support for analog input device support. This includes - not only Analog-to-Digital Converters (ADC) but also amplifiers and - analog multiplexers. - -config ADC_ADS125X - bool "TI ADS1255/ADS1256 support" - default n - depends on ADC - select SPI - -config ADS1255_FREQUENCY - int "ADS1255/ADS1256 SPI frequency" - default 1000000 - depends on ADC_ADS125X - -config ADC_PGA11X - bool "TI PGA112/3/6/7 support" - default n - depends on ADC - select SPI - ---help--- - Enables support for the PGA112, PGA113, PGA116, PGA117 Zerø-Drift - PROGRAMMABLE GAIN AMPLIFIER with MUX - -config PGA11X_SPIFREQUENCY - int "TI PGA112/3/6/7 SPI frequency" - default 1000000 - depends on ADC_PGA11X - ---help--- - PGA11x SPI frequency. - -config PGA11X_SPIMODE - int "TI PGA112/3/6/7 SPI mode" - default 0 - depends on ADC_PGA11X - ---help--- - PGA11x SPI mode. The specification says that the device operates in Mode 0 or - Mode 3. But sometimes you need to tinker with this to get things to work - correctly. Default: Mode 0 - -config PGA11X_DAISYCHAIN - bool "TI PGA112/3/6/7 daisy chain mode" - default n - depends on ADC_PGA11X - ---help--- - Enable support to use two PGA116/7's in Daisy Chain configuration. - -config PGA11X_MULTIPLE - bool "Multiple TI PGA112/3/6/7 support" - default n - depends on ADC_PGA11X && !PGA11X_DAISYCHAIN - ---help--- - Can be defined to support multiple PGA11X devices on board with separate - chip selects (not daisy chained). Each device will require a customized - SPI interface to distinguish them when SPI_SELECT is called with - devid=SPIDEV_MUX. - -config DAC - bool "Digital-to-Analog Conversion" - default n - ---help--- - Select to enable support for Digital-to-Analog Converters (DACs). - -config DAC_AD5410 - bool "AD5410 support" - default n - depends on DAC - select SPI diff --git a/nuttx/drivers/analog/Make.defs b/nuttx/drivers/analog/Make.defs deleted file mode 100644 index 89cc5bd3f..000000000 --- a/nuttx/drivers/analog/Make.defs +++ /dev/null @@ -1,87 +0,0 @@ -############################################################################ -# drivers/analog/Make.defs -# -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Don't build anything if there is no support for analog devices - -# Check for DAC devices - -ifeq ($(CONFIG_DAC),y) - -# Include the common DAC character driver - -CSRCS += dac.c - -# Include DAC device drivers - -ifeq ($(CONFIG_DAC_AD5410),y) - CSRCS += ad5410.c -endif -endif - -# Check for ADC devices - -ifeq ($(CONFIG_ADC),y) - -# Include the common ADC character driver - -CSRCS += adc.c - -# Amplifiers/multiplexers - -ifeq ($(CONFIG_ADC_PGA11X),y) - CSRCS += pga11x.c -endif - -# Include ADC device drivers - -ifeq ($(CONFIG_ADC_ADS125X),y) - CSRCS += ads1255.c -endif -endif - -# Add analog driver build support (the nested if-then-else implements an OR) - -ifeq ($(CONFIG_DAC),y) - DEPPATH += --dep-path analog - VPATH += :analog - CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} -else -ifeq ($(CONFIG_ADC),y) - DEPPATH += --dep-path analog - VPATH += :analog - CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} -endif -endif - diff --git a/nuttx/drivers/analog/ad5410.c b/nuttx/drivers/analog/ad5410.c deleted file mode 100644 index 3e925a3a9..000000000 --- a/nuttx/drivers/analog/ad5410.c +++ /dev/null @@ -1,205 +0,0 @@ -/************************************************************************************ - * arch/drivers/analog/ad5410.c - * - * Copyright (C) 2011 Li Zhuoyi. All rights reserved. - * Author: Li Zhuoyi - * History: 0.1 2011-08-05 initial version - * - * This file is a part of NuttX: - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(CONFIG_DAC_AD5410) - -#define AD5410_REG_NOP 0x00 -#define AD5410_REG_WR 0x01 -#define AD5410_REG_RD 0x02 -#define AD5410_REG_CMD 0x55 -#define AD5410_REG_RST 0x56 - -#define AD5410_CMD_REXT (1<<13) -#define AD5410_CMD_OUTEN (1<<12) -#define AD5410_CMD_SRCLK(x) (x<<8) -#define AD5410_CMD_SRSTEP(x) (x<<5) -#define AD5410_CMD_SREN (1<<4) -#define AD5410_CMD_DCEN (1<<3) -#define AD5410_CMD_420MA 0x05 -#define AD5410_CMD_020MA 0x06 -#define AD5410_CMD_024MA 0x07 - -/**************************************************************************** - * ad_private Types - ****************************************************************************/ -struct up_dev_s -{ - int devno; - FAR struct spi_dev_s *spi; /* Cached SPI device reference */ -}; - -/**************************************************************************** - * ad_private Function Prototypes - ****************************************************************************/ - -/* DAC methods */ - -static void dac_reset(FAR struct dac_dev_s *dev); -static int dac_setup(FAR struct dac_dev_s *dev); -static void dac_shutdown(FAR struct dac_dev_s *dev); -static void dac_txint(FAR struct dac_dev_s *dev, bool enable); -static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg); -static int dac_ioctl(FAR struct dac_dev_s *dev, int cmd, unsigned long arg); -static int dac_interrupt(int irq, void *context); - -/**************************************************************************** - * ad_private Data - ****************************************************************************/ - -static const struct dac_ops_s g_dacops = -{ - .ao_reset =dac_reset, - .ao_setup = dac_setup, - .ao_shutdown = dac_shutdown, - .ao_txint = dac_txint, - .ao_send = dac_send, - .ao_ioctl = dac_ioctl, -}; - -static struct up_dev_s g_dacpriv; -static struct dac_dev_s g_dacdev = -{ - .ad_ops = &g_dacops, - .ad_priv= &g_dacpriv, -}; - -/**************************************************************************** - * ad_private Functions - ****************************************************************************/ - -/* Reset the DAC device. Called early to initialize the hardware. This -* is called, before ao_setup() and on error conditions. -*/ -static void dac_reset(FAR struct dac_dev_s *dev) -{ - -} - -/* Configure the DAC. This method is called the first time that the DAC -* device is opened. This will occur when the port is first opened. -* This setup includes configuring and attaching DAC interrupts. Interrupts -* are all disabled upon return. -*/ -static int dac_setup(FAR struct dac_dev_s *dev) -{ - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; - FAR struct spi_dev_s *spi = priv->spi; - SPI_SELECT(spi, priv->devno, true); - SPI_SEND(spi,AD5410_REG_CMD); - SPI_SEND(spi,(AD5410_CMD_OUTEN|AD5410_CMD_420MA)>>8); - SPI_SEND(spi,AD5410_CMD_OUTEN|AD5410_CMD_420MA); - SPI_SELECT(spi, priv->devno, false); - return OK; -} - -/* Disable the DAC. This method is called when the DAC device is closed. -* This method reverses the operation the setup method. -*/ -static void dac_shutdown(FAR struct dac_dev_s *dev) -{ -} - -/* Call to enable or disable TX interrupts */ -static void dac_txint(FAR struct dac_dev_s *dev, bool enable) -{ -} - -static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg) -{ - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; - FAR struct spi_dev_s *spi = priv->spi; - SPI_SELECT(spi, priv->devno, true); - SPI_SEND(spi,AD5410_REG_WR); - SPI_SEND(spi,(uint8_t)(msg->am_data>>24)); - SPI_SEND(spi,(uint8_t)(msg->am_data>>16)); - SPI_SELECT(spi, priv->devno, false); - dac_txdone(&g_dacdev); - return 0; -} - -/* All ioctl calls will be routed through this method */ -static int dac_ioctl(FAR struct dac_dev_s *dev, int cmd, unsigned long arg) -{ - dbg("Fix me:Not Implemented\n"); - return 0; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_ad5410cinitialize - * - * Description: - * Initialize the selected DAC port - * - * Input Parameter: - * Port number (for hardware that has mutiple DAC interfaces) - * - * Returned Value: - * Valid ad5410 device structure reference on succcess; a NULL on failure - * - ****************************************************************************/ - -FAR struct dac_dev_s *up_ad5410initialize(FAR struct spi_dev_s *spi, unsigned int devno) -{ - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_dacdev.ad_priv; - priv->spi=spi; - priv->devno=devno; - return &g_dacdev; -} -#endif - diff --git a/nuttx/drivers/analog/adc.c b/nuttx/drivers/analog/adc.c deleted file mode 100644 index 72f19452a..000000000 --- a/nuttx/drivers/analog/adc.c +++ /dev/null @@ -1,434 +0,0 @@ -/**************************************************************************** - * drivers/analog/adc.c - * - * Copyright (C) 2011 Li Zhuoyi. All rights reserved. - * Author: Li Zhuoyi - * History: 0.1 2011-08-04 initial version - * - * Derived from drivers/can.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int adc_open(FAR struct file *filep); -static int adc_close(FAR struct file *filep); -static ssize_t adc_read(FAR struct file *, FAR char *, size_t); -static ssize_t adc_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static int adc_ioctl(FAR struct file *filep,int cmd,unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations adc_fops = -{ - adc_open, /* open */ - adc_close, /* close */ - adc_read, /* read */ - adc_write, /* write */ - 0, /* seek */ - adc_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ -/************************************************************************************ - * Name: adc_open - * - * Description: - * This function is called whenever the ADC device is opened. - * - ************************************************************************************/ - -static int adc_open(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct adc_dev_s *dev = inode->i_private; - uint8_t tmp; - int ret = OK; - - /* If the port is the middle of closing, wait until the close is finished */ - - if (sem_wait(&dev->ad_closesem) != OK) - { - ret = -errno; - } - else - { - /* Increment the count of references to the device. If this the first - * time that the driver has been opened for this device, then initialize - * the device. - */ - - tmp = dev->ad_ocount + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - } - else - { - /* Check if this is the first time that the driver has been opened. */ - - if (tmp == 1) - { - /* Yes.. perform one time hardware initialization. */ - - irqstate_t flags = irqsave(); - ret = dev->ad_ops->ao_setup(dev); - if (ret == OK) - { - /* Mark the FIFOs empty */ - - dev->ad_recv.af_head = 0; - dev->ad_recv.af_tail = 0; - - /* Finally, Enable the ADC RX interrupt */ - - dev->ad_ops->ao_rxint(dev, true); - - /* Save the new open count on success */ - - dev->ad_ocount = tmp; - } - - irqrestore(flags); - } - } - - sem_post(&dev->ad_closesem); - } - return ret; -} - -/************************************************************************************ - * Name: adc_close - * - * Description: - * This routine is called when the ADC device is closed. - * It waits for the last remaining data to be sent. - * - ************************************************************************************/ - -static int adc_close(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct adc_dev_s *dev = inode->i_private; - irqstate_t flags; - int ret = OK; - - if (sem_wait(&dev->ad_closesem) != OK) - { - ret = -errno; - } - else - { - /* Decrement the references to the driver. If the reference count will - * decrement to 0, then uninitialize the driver. - */ - - if (dev->ad_ocount > 1) - { - dev->ad_ocount--; - sem_post(&dev->ad_closesem); - } - else - { - /* There are no more references to the port */ - - dev->ad_ocount = 0; - - /* Free the IRQ and disable the ADC device */ - - flags = irqsave(); /* Disable interrupts */ - dev->ad_ops->ao_shutdown(dev); /* Disable the ADC */ - irqrestore(flags); - - sem_post(&dev->ad_closesem); - } - } - return ret; -} - -/**************************************************************************** - * Name: adc_read - ****************************************************************************/ - -static ssize_t adc_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct adc_dev_s *dev = inode->i_private; - size_t nread; - irqstate_t flags; - int ret = 0; - int msglen; - - avdbg("buflen: %d\n", (int)buflen); - - if (buflen % 5 == 0) - msglen = 5; - else if (buflen % 4 == 0) - msglen = 4; - else if (buflen % 3 == 0) - msglen = 3; - else if (buflen % 2 == 0) - msglen = 2; - else if (buflen == 1) - msglen = 1; - else - msglen = 5; - - if (buflen >= msglen) - { - /* Interrupts must be disabled while accessing the ad_recv FIFO */ - - flags = irqsave(); - while (dev->ad_recv.af_head == dev->ad_recv.af_tail) - { - /* The receive FIFO is empty -- was non-blocking mode selected? */ - - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto return_with_irqdisabled; - } - - /* Wait for a message to be received */ - - dev->ad_nrxwaiters++; - ret = sem_wait(&dev->ad_recv.af_sem); - dev->ad_nrxwaiters--; - if (ret < 0) - { - ret = -errno; - goto return_with_irqdisabled; - } - } - - /* The ad_recv FIFO is not empty. Copy all buffered data that will fit - * in the user buffer. - */ - - nread = 0; - do - { - FAR struct adc_msg_s *msg = &dev->ad_recv.af_buffer[dev->ad_recv.af_head]; - - /* Will the next message in the FIFO fit into the user buffer? */ - - if (nread + msglen > buflen) - { - /* No.. break out of the loop now with nread equal to the actual - * number of bytes transferred. - */ - - break; - } - - /* Copy the message to the user buffer */ - - if (msglen == 1) - { - /* Only one channel,read highest 8-bits */ - - buffer[nread] = msg->am_data >> 24; - } - else if (msglen == 2) - { - /* Only one channel, read highest 16-bits */ - - *(int16_t *)&buffer[nread] = msg->am_data >> 16; - } - else if (msglen == 3) - { - /* Read channel highest 16-bits */ - - buffer[nread] = msg->am_channel; - *(int16_t *)&buffer[nread + 1] = msg->am_data >> 16; - } - else if (msglen == 4) - { - /* read channel highest 24-bits */ - - *(int32_t *)&buffer[nread] = msg->am_data; - buffer[nread] = msg->am_channel; - } - else - { - /* Read all */ - - *(int32_t *)&buffer[nread + 1] = msg->am_data; - buffer[nread] = msg->am_channel; - } - nread += msglen; - - /* Increment the head of the circular message buffer */ - - if (++dev->ad_recv.af_head >= CONFIG_ADC_FIFOSIZE) - { - dev->ad_recv.af_head = 0; - } - } - while (dev->ad_recv.af_head != dev->ad_recv.af_tail); - - /* All on the messages have bee transferred. Return the number of bytes - * that were read. - */ - - ret = nread; - -return_with_irqdisabled: - irqrestore(flags); - } - - avdbg("Returning: %d\n", ret); - return ret; -} - -/************************************************************************************ - * Name: adc_write - ************************************************************************************/ - -static ssize_t adc_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) -{ - return 0; -} - -/************************************************************************************ - * Name: adc_ioctl - ************************************************************************************/ - -static int adc_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct adc_dev_s *dev = inode->i_private; - int ret = OK; - - ret = dev->ad_ops->ao_ioctl(dev, cmd, arg); - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: adc_receive - ****************************************************************************/ - -int adc_receive(FAR struct adc_dev_s *dev, uint8_t ch, int32_t data) -{ - FAR struct adc_fifo_s *fifo = &dev->ad_recv; - int nexttail; - int err = -ENOMEM; - - /* Check if adding this new message would over-run the drivers ability to enqueue - * read data. - */ - - nexttail = fifo->af_tail + 1; - if (nexttail >= CONFIG_ADC_FIFOSIZE) - { - nexttail = 0; - } - - /* Refuse the new data if the FIFO is full */ - - if (nexttail != fifo->af_head) - { - /* Add the new, decoded ADC sample at the tail of the FIFO */ - - fifo->af_buffer[fifo->af_tail].am_channel = ch; - fifo->af_buffer[fifo->af_tail].am_data = data; - - /* Increment the tail of the circular buffer */ - - fifo->af_tail = nexttail; - - if (dev->ad_nrxwaiters > 0) - { - sem_post(&fifo->af_sem); - } - - err = OK; - } - return err; -} - -/**************************************************************************** - * Name: adc_register - ****************************************************************************/ - -int adc_register(FAR const char *path, FAR struct adc_dev_s *dev) -{ - /* Initialize the ADC device structure */ - - dev->ad_ocount = 0; - - sem_init(&dev->ad_recv.af_sem, 0, 0); - sem_init(&dev->ad_closesem, 0, 1); - - dev->ad_ops->ao_reset(dev); - - return register_driver(path, &adc_fops, 0444, dev); -} diff --git a/nuttx/drivers/analog/ads1255.c b/nuttx/drivers/analog/ads1255.c deleted file mode 100644 index 374decc54..000000000 --- a/nuttx/drivers/analog/ads1255.c +++ /dev/null @@ -1,335 +0,0 @@ -/************************************************************************************ - * arch/drivers/analog/ads1255.c - * - * Copyright (C) 2011 Li Zhuoyi. All rights reserved. - * Author: Li Zhuoyi - * History: 0.1 2011-08-05 initial version - * 0.2 2011-08-25 fix bug in g_adcdev (cd_ops -> ad_ops,cd_priv -> ad_priv) - * - * This file is a part of NuttX: - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(CONFIG_ADC_ADS1255) - -#define ADS125X_BUFON 0x02 -#define ADS125X_BUFOFF 0x00 - -#define ADS125X_PGA1 0x00 -#define ADS125X_PGA2 0x01 -#define ADS125X_PGA4 0x02 -#define ADS125X_PGA8 0x03 -#define ADS125X_PGA16 0x04 -#define ADS125X_PGA32 0x05 -#define ADS125X_PGA64 0x06 - -#define ADS125X_RDATA 0x01 //Read Data -#define ADS125X_RDATAC 0x03 //Read Data Continuously -#define ADS125X_SDATAC 0x0F //Stop Read Data Continuously -#define ADS125X_RREG 0x10 //Read from REG -#define ADS125X_WREG 0x50 //Write to REG -#define ADS125X_SELFCAL 0xF0 //Offset and Gain Self-Calibration -#define ADS125X_SELFOCAL 0xF1 //Offset Self-Calibration -#define ADS125X_SELFGCAL 0xF2 //Gain Self-Calibration -#define ADS125X_SYSOCAL 0xF3 //System Offset Calibration -#define ADS125X_SYSGCAL 0xF4 //System Gain Calibration -#define ADS125X_SYNC 0xFC //Synchronize the A/D Conversion -#define ADS125X_STANDBY 0xFD //Begin Standby Mode -#define ADS125X_RESET 0xFE //Reset to Power-Up Values -#define ADS125X_WAKEUP 0xFF //Completes SYNC and Exits Standby Mode - -#ifndef CONFIG_ADS1255_FREQUENCY -#define CONFIG_ADS1255_FREQUENCY 1000000 -#endif -#ifndef CONFIG_ADS1255_MUX -#define CONFIG_ADS1255_MUX 0x01 -#endif -#ifndef CONFIG_ADS1255_CHMODE -#define CONFIG_ADS1255_CHMODE 0x00 -#endif -#ifndef CONFIG_ADS1255_BUFON -#define CONFIG_ADS1255_BUFON 1 -#endif -#ifndef CONFIG_ADS1255_PGA -#define CONFIG_ADS1255_PGA ADS125X_PGA2 -#endif -#ifndef CONFIG_ADS1255_SPS -#define CONFIG_ADS1255_SPS 50 -#endif - -/**************************************************************************** - * ad_private Types - ****************************************************************************/ - -struct up_dev_s -{ - uint8_t channel; - uint32_t sps; - uint8_t pga; - uint8_t buf; - const uint8_t *mux; - int irq; - int devno; - FAR struct spi_dev_s *spi; /* Cached SPI device reference */ -}; - -/**************************************************************************** - * ad_private Function Prototypes - ****************************************************************************/ - -/* ADC methods */ - -static void adc_reset(FAR struct adc_dev_s *dev); -static int adc_setup(FAR struct adc_dev_s *dev); -static void adc_shutdown(FAR struct adc_dev_s *dev); -static void adc_rxint(FAR struct adc_dev_s *dev, bool enable); -static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg); -static int adc_interrupt(int irq, void *context); - -/**************************************************************************** - * ad_private Data - ****************************************************************************/ - -static const struct adc_ops_s g_adcops = -{ - .ao_reset = adc_reset, /* ao_reset */ - .ao_setup = adc_setup, /* ao_setup */ - .ao_shutdown = adc_shutdown, /* ao_shutdown */ - .ao_rxint = adc_rxint, /* ao_rxint */ - .ao_ioctl = adc_ioctl /* ao_read */ -}; - -static struct up_dev_s g_adcpriv = -{ - .mux = (const uint8_t []) - { - CONFIG_ADS1255_MUX,0 - }, - .sps = CONFIG_ADS1255_SPS, - .channel = 0, - .irq = CONFIG_ADS1255_IRQ, -}; - -static struct adc_dev_s g_adcdev = -{ - .ad_ops = &g_adcops, - .ad_priv= &g_adcpriv, -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -static uint8_t getspsreg(uint16_t sps) -{ - static const unsigned short sps_tab[]= - { - 3,7,12,20,27,40,55,80,300,750,1500,3000,5000,10000,20000,65535, - }; - static const unsigned char sps_reg[]= - { - 0x03,0x13,0x23,0x33,0x43,0x53,0x63,0x72,0x82,0x92,0xa1,0xb0,0xc0,0xd0,0xe0,0xf0, - }; - int i; - for (i=0; i<16; i++) - { - if (spsad_priv; - FAR struct spi_dev_s *spi = priv->spi; - - SPI_SETMODE(spi, SPIDEV_MODE1); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_ADS1255_FREQUENCY); - usleep(1000); - SPI_SELECT(spi, priv->devno, true); - SPI_SEND(spi,ADS125X_WREG+0x03); //WRITE SPS REG - SPI_SEND(spi,0x00); //count=1 - SPI_SEND(spi,0x63); - SPI_SELECT(spi, priv->devno, false); -} - -/* Configure the ADC. This method is called the first time that the ADC -* device is opened. This will occur when the port is first opened. -* This setup includes configuring and attaching ADC interrupts. Interrupts -* are all disabled upon return. -*/ - -static int adc_setup(FAR struct adc_dev_s *dev) -{ - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; - FAR struct spi_dev_s *spi = priv->spi; - int ret = irq_attach(priv->irq, adc_interrupt); - if (ret == OK) - { - SPI_SELECT(spi, priv->devno, true); - SPI_SEND(spi,ADS125X_WREG); //WRITE REG from 0 - SPI_SEND(spi,0x03); //count=4+1 - if (priv->buf) - SPI_SEND(spi,ADS125X_BUFON); //REG0 STATUS BUFFER ON - else - SPI_SEND(spi,ADS125X_BUFOFF); - SPI_SEND(spi,priv->mux[0]); - SPI_SEND(spi,priv->pga); //REG2 ADCON PGA=2 - SPI_SEND(spi,getspsreg(priv->sps)); - usleep(1000); - SPI_SEND(spi,ADS125X_SELFCAL); - SPI_SELECT(spi, priv->devno, false); - up_enable_irq(priv->irq); - } - return ret; -} - -/* Disable the ADC. This method is called when the ADC device is closed. -* This method reverses the operation the setup method. -*/ - -static void adc_shutdown(FAR struct adc_dev_s *dev) -{ - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; - up_disable_irq(priv->irq); - irq_detach(priv->irq); -} - -/* Call to enable or disable RX interrupts */ - -static void adc_rxint(FAR struct adc_dev_s *dev, bool enable) -{ - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; - if (enable) - up_enable_irq(priv->irq); - else - up_disable_irq(priv->irq); -} - -/* All ioctl calls will be routed through this method */ - -static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) -{ - dbg("Fix me:Not Implemented\n"); - return 0; -} - -static int adc_interrupt(int irq, void *context) -{ - uint32_t regval; - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_adcdev.ad_priv; - FAR struct spi_dev_s *spi = priv->spi; - unsigned char buf[4]; - unsigned char ch; - - SPI_SELECT(spi, priv->devno, true); - SPI_SEND(spi,ADS125X_RDATA); - up_udelay(10); - buf[3]=SPI_SEND(spi,0xff); - buf[2]=SPI_SEND(spi,0xff); - buf[1]=SPI_SEND(spi,0xff); - buf[0]=0; - - priv->channel++; - ch = priv->mux[priv->channel]; - if ( ch == 0 ) - { - priv->channel=0; - ch = priv->mux[0]; - } - - SPI_SEND(spi,ADS125X_WREG+0x01); - SPI_SEND(spi,0x00); - SPI_SEND(spi,ch); - SPI_SEND(spi,ADS125X_SYNC); - up_udelay(2); - SPI_SEND(spi,ADS125X_WAKEUP); - SPI_SELECT(spi, priv->devno, false); - - adc_receive(&g_adcdev,priv->channel,*(int32_t *)buf); - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_ads1255initialize - * - * Description: - * Initialize the selected adc port - * - * Input Parameter: - * Port number (for hardware that has mutiple adc interfaces) - * - * Returned Value: - * Valid can device structure reference on succcess; a NULL on failure - * - ****************************************************************************/ - -FAR struct adc_dev_s *up_ads1255initialize(FAR struct spi_dev_s *spi, unsigned int devno) -{ - FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_adcdev.ad_priv; - - /* Driver state data */ - - priv->spi = spi; - priv->devno = devno; - return &g_adcdev; -} -#endif - diff --git a/nuttx/drivers/analog/dac.c b/nuttx/drivers/analog/dac.c deleted file mode 100644 index e1fc3049f..000000000 --- a/nuttx/drivers/analog/dac.c +++ /dev/null @@ -1,499 +0,0 @@ -/**************************************************************************** - * drivers/analog/dac.c - * - * Copyright (C) 2011 Li Zhuoyi. All rights reserved. - * Author: Li Zhuoyi - * History: 0.1 2011-08-04 initial version - * - * Derived from drivers/can.c - * - * Copyright (C) 2008-2009Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define HALF_SECOND_MSEC 500 -#define HALF_SECOND_USEC 500000L - - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int dac_open(FAR struct file *filep); -static int dac_close(FAR struct file *filep); -static ssize_t dac_read(FAR struct file *, FAR char *, size_t); -static ssize_t dac_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static int dac_ioctl(FAR struct file *filep,int cmd,unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations dac_fops = -{ - dac_open, - dac_close, - dac_read, - dac_write, - 0, - dac_ioctl -#ifndef CONFIG_DISABLE_POLL - , 0 -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ -/************************************************************************************ - * Name: dac_open - * - * Description: - * This function is called whenever the DAC device is opened. - * - ************************************************************************************/ - -static int dac_open(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct dac_dev_s *dev = inode->i_private; - uint8_t tmp; - int ret = OK; - - /* If the port is the middle of closing, wait until the close is finished */ - - if (sem_wait(&dev->ad_closesem) != OK) - { - ret = -errno; - } - else - { - /* Increment the count of references to the device. If this the first - * time that the driver has been opened for this device, then initialize - * the device. - */ - - tmp = dev->ad_ocount + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - } - else - { - /* Check if this is the first time that the driver has been opened. */ - - if (tmp == 1) - { - /* Yes.. perform one time hardware initialization. */ - - irqstate_t flags = irqsave(); - ret = dev->ad_ops->ao_setup(dev); - if (ret == OK) - { - /* Mark the FIFOs empty */ - - dev->ad_xmit.af_head = 0; - dev->ad_xmit.af_tail = 0; - - /* Save the new open count on success */ - - dev->ad_ocount = tmp; - } - irqrestore(flags); - } - } - sem_post(&dev->ad_closesem); - } - return ret; -} - -/************************************************************************************ - * Name: dac_close - * - * Description: - * This routine is called when the DAC device is closed. - * It waits for the last remaining data to be sent. - * - ************************************************************************************/ - -static int dac_close(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct dac_dev_s *dev = inode->i_private; - irqstate_t flags; - int ret = OK; - - if (sem_wait(&dev->ad_closesem) != OK) - { - ret = -errno; - } - else - { - /* Decrement the references to the driver. If the reference count will - * decrement to 0, then uninitialize the driver. - */ - - if (dev->ad_ocount > 1) - { - dev->ad_ocount--; - sem_post(&dev->ad_closesem); - } - else - { - /* There are no more references to the port */ - - dev->ad_ocount = 0; - - /* Now we wait for the transmit FIFO to clear */ - - while (dev->ad_xmit.af_head != dev->ad_xmit.af_tail) - { -#ifndef CONFIG_DISABLE_SIGNALS - usleep(HALF_SECOND_USEC); -#else - up_mdelay(HALF_SECOND_MSEC); -#endif - } - - /* Free the IRQ and disable the DAC device */ - - flags = irqsave(); /* Disable interrupts */ - dev->ad_ops->ao_shutdown(dev); /* Disable the DAC */ - irqrestore(flags); - - sem_post(&dev->ad_closesem); - } - } - return ret; -} - -/**************************************************************************** - * Name: dac_read - ****************************************************************************/ - -static ssize_t dac_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - return 0; -} - -/************************************************************************************ - * Name: dac_xmit - * - * Description: - * Send the message at the head of the ad_xmit FIFO - * - * Assumptions: - * Called with interrupts disabled - * - ************************************************************************************/ - -static int dac_xmit(FAR struct dac_dev_s *dev) -{ - bool enable = false; - int ret = OK; - - /* Check if the xmit FIFO is empty */ - - if (dev->ad_xmit.af_head != dev->ad_xmit.af_tail) - { - /* Send the next message at the head of the FIFO */ - - ret = dev->ad_ops->ao_send(dev, &dev->ad_xmit.af_buffer[dev->ad_xmit.af_head]); - - /* Make sure the TX done interrupts are enabled */ - - enable = (ret == OK ? true : false); - } - dev->ad_ops->ao_txint(dev, enable); - return ret; -} - -/************************************************************************************ - * Name: dac_write - ************************************************************************************/ - -static ssize_t dac_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct dac_dev_s *dev = inode->i_private; - FAR struct dac_fifo_s *fifo = &dev->ad_xmit; - FAR struct dac_msg_s *msg; - bool empty = false; - ssize_t nsent = 0; - irqstate_t flags; - int nexttail; - int msglen; - int ret = 0; - - /* Interrupts must disabled throughout the following */ - - flags = irqsave(); - - /* Check if the TX FIFO was empty when we started. That is a clue that we have - * to kick off a new TX sequence. - */ - - empty = (fifo->af_head == fifo->af_tail); - - /* Add the messages to the FIFO. Ignore any trailing messages that are - * shorter than the minimum. - */ - - if (buflen % 5 ==0 ) - msglen=5; - else if (buflen % 4 ==0 ) - msglen=4; - else if (buflen % 3 ==0 ) - msglen=3; - else if (buflen % 2 ==0 ) - msglen=2; - else if (buflen == 1) - msglen=1; - else - msglen=5; - - while ((buflen - nsent) >= msglen ) - { - /* Check if adding this new message would over-run the drivers ability to enqueue - * xmit data. - */ - - nexttail = fifo->af_tail + 1; - if (nexttail >= CONFIG_DAC_FIFOSIZE) - { - nexttail = 0; - } - - /* If the XMIT fifo becomes full, then wait for space to become available */ - - while (nexttail == fifo->af_head) - { - /* The transmit FIFO is full -- was non-blocking mode selected? */ - - if (filep->f_oflags & O_NONBLOCK) - { - if (nsent == 0) - { - ret = -EAGAIN; - } - else - { - ret = nsent; - } - goto return_with_irqdisabled; - } - - /* If the FIFO was empty when we started, then we will have - * start the XMIT sequence to clear the FIFO. - */ - - if (empty) - { - dac_xmit(dev); - } - - /* Wait for a message to be sent */ - - do - { - ret = sem_wait(&fifo->af_sem); - if (ret < 0 && errno != EINTR) - { - ret = -errno; - goto return_with_irqdisabled; - } - } - while (ret < 0); - - /* Re-check the FIFO state */ - - empty = (fifo->af_head == fifo->af_tail); - } - - /* We get here if there is space at the end of the FIFO. Add the new - * CAN message at the tail of the FIFO. - */ - - if (msglen==5) - { - msg = (FAR struct dac_msg_s *)&buffer[nsent]; - memcpy(&fifo->af_buffer[fifo->af_tail], msg, msglen); - } - else if(msglen == 4) - { - fifo->af_buffer[fifo->af_tail].am_channel=buffer[nsent]; - fifo->af_buffer[fifo->af_tail].am_data=*(uint32_t *)&buffer[nsent]; - fifo->af_buffer[fifo->af_tail].am_data&=0xffffff00; - } - else if(msglen == 3) - { - fifo->af_buffer[fifo->af_tail].am_channel=buffer[nsent]; - fifo->af_buffer[fifo->af_tail].am_data=(*(uint16_t *)&buffer[nsent+1]); - fifo->af_buffer[fifo->af_tail].am_data<<=16; - } - else if(msglen == 2) - { - fifo->af_buffer[fifo->af_tail].am_channel=0; - fifo->af_buffer[fifo->af_tail].am_data=(*(uint16_t *)&buffer[nsent]); - fifo->af_buffer[fifo->af_tail].am_data<<=16; - } - else if(msglen == 1) - { - fifo->af_buffer[fifo->af_tail].am_channel=0; - fifo->af_buffer[fifo->af_tail].am_data=buffer[nsent]; - fifo->af_buffer[fifo->af_tail].am_data<<=24; - } - /* Increment the tail of the circular buffer */ - - fifo->af_tail = nexttail; - - /* Increment the number of bytes that were sent */ - - nsent += msglen; - } - - /* We get here after all messages have been added to the FIFO. Check if - * we need to kick of the XMIT sequence. - */ - - if (empty) - { - dac_xmit(dev); - } - - /* Return the number of bytes that were sent */ - - ret = nsent; - -return_with_irqdisabled: - irqrestore(flags); - return ret; -} - -/************************************************************************************ - * Name: dac_ioctl - ************************************************************************************/ - -static int dac_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct dac_dev_s *dev = inode->i_private; - int ret = OK; - - ret = dev->ad_ops->ao_ioctl(dev, cmd, arg); - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/************************************************************************************ - * Name: dac_txdone - * - * Description: - * Called from the DAC interrupt handler at the completion of a send operation. - * - * Return: - * OK on success; a negated errno on failure. - * - ************************************************************************************/ - -int dac_txdone(FAR struct dac_dev_s *dev) -{ - int ret = -ENOENT; - - /* Verify that the xmit FIFO is not empty */ - - if (dev->ad_xmit.af_head != dev->ad_xmit.af_tail) - { - /* Remove the message at the head of the xmit FIFO */ - - if (++dev->ad_xmit.af_head >= CONFIG_DAC_FIFOSIZE) - { - dev->ad_xmit.af_head = 0; - } - - /* Send the next message in the FIFO */ - - ret = dac_xmit(dev); - if (ret == OK) - { - /* Inform any waiting threads that new xmit space is available */ - - ret = sem_post(&dev->ad_xmit.af_sem); - } - } - return ret; -} - -int dac_register(FAR const char *path, FAR struct dac_dev_s *dev) -{ - /* Initialize the DAC device structure */ - - dev->ad_ocount = 0; - - sem_init(&dev->ad_xmit.af_sem, 0, 0); - sem_init(&dev->ad_closesem, 0, 1); - - dev->ad_ops->ao_reset(dev); - - return register_driver(path, &dac_fops, 0555, dev); -} - diff --git a/nuttx/drivers/analog/pga11x.c b/nuttx/drivers/analog/pga11x.c deleted file mode 100644 index 7bb4a11bb..000000000 --- a/nuttx/drivers/analog/pga11x.c +++ /dev/null @@ -1,793 +0,0 @@ -/**************************************************************************** - * drivers/analog/pga11x.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "PGA112, PGA113, PGA116, PGA117: Zerø-Drift PROGRAMMABLE GAIN AMPLIFIER - * with MUX", SBOS424B, March 2008, Revised September 2008, Texas - * Instruments Incorporated" - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include - -#if defined(CONFIG_ADC) && defined(CONFIG_ADC_PGA11X) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* The PGA112/PGA113 have a three-wire SPI digital interface; the - * PGA116/PGA117 have a four-wire SPI digital interface. The PGA116/117 also - * have daisy-chain capability (The PGA112/PGA113 can be used as the last device - * in a daisy-chain as shown if write-only communication is acceptable). - */ - -/* PGA11x commands (PGA112/PGA113) */ - -#define PGA11X_CMD_READ 0x6a00 -#define PGA11X_CMD_WRITE 0x2a00 -#define PGA11X_CMD_NOOP 0x0000 -#define PGA11X_CMD_SDN_DIS 0xe100 -#define PGA11X_CMD_SDN_EN 0xe1f1 - -/* SPI Daisy-Chain Commands (PGA116/PGA117) */ - -#define PGA11X_DCCMD_SELECTOR 0x8000 -#define PGA11X_DCCMD_NOOP (PGA11X_DCCMD_SELECTOR | PGA11X_CMD_NOOP) -#define PGA11X_DCCMD_SDN_DIS (PGA11X_DCCMD_SELECTOR | PGA11X_CMD_SDN_DIS) -#define PGA11X_DCCMD_SDN_EN (PGA11X_DCCMD_SELECTOR | PGA11X_CMD_SDN_EN) -#define PGA11X_DCCMD_READ (PGA11X_DCCMD_SELECTOR | PGA11X_CMD_READ) -#define PGA11X_DCCMD_WRITE (PGA11X_DCCMD_SELECTOR | PGA11X_CMD_WRITE) - -/* Write command Gain Selection Bits (PGA112/PGA113) - * - * the PGA112 and PGA116 provide binary gain selections (1, 2, 4, 8, 16, 32, - * 64, 128); the PGA113 and PGA117 provide scope gain selections (1, 2, 5, 10, - * 20, 50, 100, 200). - */ - -#define PGA11X_GAIN_SHIFT (4) /* Bits 4-7: Gain Selection Bits */ -#define PGA11X_GAIN_MASK (15 << PGA11X_GAIN_SHIFT) - -/* Write command Mux Channel Selection Bits - * - * The PGA112/PGA113 have a two-channel input MUX; the PGA116/PGA117 have a - * 10-channel input MUX. - */ - -#define PGA11X_CHAN_SHIFT (0) /* Bits 0-3: Channel Selection Bits */ -#define PGA11X_CHAN_MASK (15 << PGA11X_CHAN_SHIFT) - -/* Other definitions ********************************************************/ - -#define SPI_DUMMY 0xff - -/* Debug ********************************************************************/ -/* Check if (non-standard) SPI debug is enabled */ - -#ifndef CONFIG_DEBUG -# undef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_SPI -#endif - -#ifdef CONFIG_DEBUG_SPI -# define spidbg dbg -# ifdef CONFIG_DEBUG_VERBOSE -# define spivdbg dbg -# else -# define spivdbg(x...) -# endif -#else -# define spidbg(x...) -# define spivdbg(x...) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pga11x_configure - * - * Description: - * Configure the SPI bus as needed for the PGA11x device. - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void pga11x_configure(FAR struct spi_dev_s *spi) -{ - spivdbg("MODE: %d BITS: 8 Frequency: %d\n", - CONFIG_PGA11X_SPIMODE, CONFIG_PGA11X_SPIFREQUENCY); - - /* Call the setfrequency, setbits, and setmode methods to make sure that - * the SPI is properly configured for the device. - */ - - SPI_SETMODE(spi, CONFIG_PGA11X_SPIMODE); - SPI_SETBITS(spi, 8); - (void)SPI_SETFREQUENCY(spi, CONFIG_PGA11X_SPIFREQUENCY); -} - -/**************************************************************************** - * Name: pga11x_lock - * - * Description: - * Lock the SPI bus and configure it as needed for the PGA11x device. - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void pga11x_lock(FAR struct spi_dev_s *spi) -{ - spivdbg("Locking\n"); - - /* On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of - * transfers. The bus should be locked before the chip is selected. - * - * This is a blocking call and will not return until we have exclusiv access to - * the SPI buss. We will retain that exclusive access until the bus is unlocked. - */ - - SPI_LOCK(spi, true); - - /* After locking the SPI bus, the we also need call the setfrequency, setbits, and - * setmode methods to make sure that the SPI is properly configured for the device. - * If the SPI buss is being shared, then it may have been left in an incompatible - * state. - */ - - pga11x_configure(spi); -} -#else -# define pga11x_lock(spi) -#endif - -/**************************************************************************** - * Name: pga11x_unlock - * - * Description: - * Lock the SPI bus and configure it as needed for the PGA11x device. - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static inline void pga11x_unlock(FAR struct spi_dev_s *spi) -{ - spivdbg("Unlocking\n"); - - SPI_LOCK(spi, false); -} -#else -# define pga11x_unlock(spi) -#endif - -/**************************************************************************** - * Name: pga11x_send16 - * - * Description: - * Send 16 bits of data, ignoring any returned data - * - * Input Parameters: - * spi - PGA11X driver instance - * word - The data to send - * - * Returned Value: - * None - * - * Assumptions: - * The bus is locked and the device is selected - * - ****************************************************************************/ - -static void pga11x_send16(FAR struct spi_dev_s *spi, uint16_t word) -{ - spivdbg("Send %04x\n", word); - - /* The logical interface is 16-bits wide. However, this driver uses a - * 8-bit configuration for greaer portability. - * - * Send the MS byte first. Then the LS byte. - */ - - SPI_SEND(spi, word >> 8); - SPI_SEND(spi, word & 0xff); -} - -/**************************************************************************** - * Name: pga11x_recv16 - * - * Description: - * Receive 16 bits of data. - * - * Input Parameters: - * spi - PGA11X driver instance - * - * Returned Value: - * The received 16-bit value - * - * Assumptions: - * The bus is locked and the device is selected - * - ****************************************************************************/ - -static uint16_t pga11x_recv16(FAR struct spi_dev_s *spi) -{ - uint8_t msb; - uint8_t lsb; - - /* The logical interface is 16-bits wide. However, this driver uses a - * 8-bit configuration for greaer portability. - * - * Send a dummy byte and receive MS byte first. Then the LS byte. - */ - - msb = SPI_SEND(spi, SPI_DUMMY); - lsb = SPI_SEND(spi, SPI_DUMMY); - spivdbg("Received %02x %02x\n", msb, lsb); - - return ((uint16_t)msb << 8) | (uint16_t)lsb; -} - -/**************************************************************************** - * Name: pga11x_write - * - * Description: - * Send a 16-bit command. - * - * Input Parameters: - * spi - PGA11X driver instance - * cmd - PGA11X command (non-daisy chained) - * u1cmd - PGA11X U1 command (daisy chained) - * u2cmd - PGA11X U2 command (daisy chained) - * - * Returned Value: - * The received 16-bit value - * - * Assumptions: - * The device is NOT selected and the NOT bus is locked. - * - ****************************************************************************/ - -#ifndef CONFIG_PGA11X_DAISYCHAIN -static void pga11x_write(FAR struct spi_dev_s *spi, uint16_t cmd) -{ - spivdbg("cmd %04x\n", cmd); - - /* Lock, select, send the 16-bit command, de-select, and un-lock. */ - - pga11x_lock(spi); - SPI_SELECT(spi, SPIDEV_MUX, true); - pga11x_send16(spi, cmd); - SPI_SELECT(spi, SPIDEV_MUX, false); - pga11x_unlock(spi); -} -#else -static void pga11x_write(FAR struct spi_dev_s *spi, uint16_t u1cmd, uint16_t u2cmd) -{ - spivdbg("U1 cmd: %04x U2 cmd: %04x\n", u1cmd, u2cmd); - - /* Lock, select, send the U2 16-bit command, the U1 16-bit command, de-select, - * and un-lock. - */ - - pga11x_lock(spi); - SPI_SELECT(spi, SPIDEV_MUX, true); - pga11x_send16(spi, u2cmd); - pga11x_send16(spi, u1cmd); - SPI_SELECT(spi, SPIDEV_MUX, false); - pga11x_unlock(spi); -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pga11x_initialize - * - * Description: - * Initialize the PGA117 amplifier/multiplexer(s). - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * - * Returned Value: - * On success, a non-NULL opaque handle is returned; a NULL is returned - * on any failure. This handle may be used with the other PGA117 interface - * functions to control the multiplexer - * - ****************************************************************************/ - -PGA11X_HANDLE pga11x_initialize(FAR struct spi_dev_s *spi) -{ - spivdbg("Entry\n"); - - /* Configure the SPI us for the device. Do this now only if the PGA11X is - * the only device on the bus. - */ - -#ifdef CONFIG_SPI_OWNBUS - pga11x_configure(spi); -#endif - - /* No other special state is required, just return the SPI driver instance - * as the handle. This gives us a place to extend functionality in the - * future if neccessary. - */ - - return (PGA11X_HANDLE)spi; -} - -/**************************************************************************** - * Name: pga11x_select - * - * Description: - * Select an input channel and gain for all PGA11xs. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_select() configures - * both chips in the daisy-chain. pga11x_uselect() is provided to support - * configuring the parts in the daisychain independently. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * settings - New channel and gain settings - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -int pga11x_select(PGA11X_HANDLE handle, - FAR const struct pga11x_settings_s *settings) -{ -#ifndef CONFIG_PGA11X_DAISYCHAIN - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - uint16_t cmd; - - DEBUGASSERT(handle && settings); - spivdbg("channel: %d gain: %d\n", settings->channel, settings->gain); - - /* Format the command */ - - cmd = PGA11X_CMD_WRITE | - ((uint16_t)settings->channel << PGA11X_CHAN_SHIFT) | - ((uint16_t)settings->gain << PGA11X_GAIN_SHIFT); - - /* Send the command */ - - pga11x_write(spi, cmd); - return OK; -#else - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - uint16_t u1cmd; - uint16_t u2cmd; - - DEBUGASSERT(handle && settings); - spivdbg("U1 channel: %d gain: %d\n", settings->u1.channel, settings->u1.gain); - spivdbg("U1 channel: %d gain: %d\n", settings->u1.channel, settings->u1.gain); - - /* Format the commands */ - - u1cmd = PGA11X_CMD_WRITE | - ((uint16_t)settings->u1.channel << PGA11X_CHAN_SHIFT) | - ((uint16_t)settings->u1.gain << PGA11X_GAIN_SHIFT); - - u2cmd = PGA11X_DCCMD_WRITE | - ((uint16_t)settings->u2.channel << PGA11X_CHAN_SHIFT) | - ((uint16_t)settings->u2.gain << PGA11X_GAIN_SHIFT); - - /* Send the command */ - - pga11x_write(spi, u1cmd, u2cmd); - return OK; -#endif -} - -/**************************************************************************** - * Name: pga11x_uselect - * - * Description: - * Select an input channel and gain for one PGA11x. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_uselect() configures - * one chips in the daisy-chain. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * pos - Position of the chip in the daisy chain (0 or 1) - * settings - New channel and gain settings - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -#ifdef CONFIG_PGA11X_DAISYCHAIN -int pga11x_uselect(PGA11X_HANDLE handle, int pos, - FAR const struct pga11x_usettings_s *settings) -{ - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - uint16_t u1cmd; - uint16_t u2cmd; - - spivdbg("channel: %d gain: %d\n", settings->channel, settings->gain); - DEBUGASSERT(handle); - - /* Format the commands */ - - if (pos == 0) - { - u1cmd = PGA11X_CMD_WRITE | - ((uint16_t)settings->channel << PGA11X_CHAN_SHIFT) | - ((uint16_t)settings->gain << PGA11X_GAIN_SHIFT); - u2cmd = PGA11X_DCCMD_NOOP; - } - else /* if (pos == 1) */ - { - u1cmd = PGA11X_CMD_NOOP; - u2cmd = PGA11X_DCCMD_WRITE | - ((uint16_t)settings->channel << PGA11X_CHAN_SHIFT) | - ((uint16_t)settings->gain << PGA11X_GAIN_SHIFT); - } - - /* Send the command */ - - pga11x_write(spi, u1cmd, u2cmd); - return OK; -} -#endif - -/**************************************************************************** - * Name: pga11x_read - * - * Description: - * Read from all PGA117 amplifier/multiplexers. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_read() reads from - * both chips in the daisy-chain. pga11x_uread() is provided to support - * accessing the parts independently. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * settings - Returned channel and gain settings - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -int pga11x_read(PGA11X_HANDLE handle, FAR struct pga11x_settings_s *settings) -{ -#ifdef CONFIG_PGA11X_DAISYCHAIN - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - uint16_t u1value; - uint16_t u2value; - - spivdbg("Entry\n"); - DEBUGASSERT(handle && settings); - - /* Lock the bus and read the configuration */ - - pga11x_lock(spi); - - /* Select, send the 16-bit command, the 16-bit daisy-chain command, and - * then de-select the part. I do not know if de-selection between word - * transfers is required. However, it is shown in the timing diagrams - * for the part. - */ - - SPI_SELECT(spi, SPIDEV_MUX, true); - pga11x_send16(spi, PGA11X_CMD_READ); - pga11x_send16(spi, PGA11X_DCCMD_READ); - SPI_SELECT(spi, SPIDEV_MUX, false); - - /* Re-select, get the returned values, de-select, and unlock */ - - SPI_SELECT(spi, SPIDEV_MUX, true); - u2value = pga11x_recv16(spi); - u1value = pga11x_recv16(spi); - SPI_SELECT(spi, SPIDEV_MUX, false); - pga11x_unlock(spi); - - /* Decode the returned value */ - - spivdbg("Returning %04x %04x\n", u2value, u1value); - settings->u1.channel = (uint8_t)((u1value & PGA11X_CHAN_MASK) >> PGA11X_CHAN_SHIFT); - settings->u1.gain = (uint8_t)((u1value & PGA11X_GAIN_MASK) >> PGA11X_GAIN_SHIFT); - settings->u2.channel = (uint8_t)((u2value & PGA11X_CHAN_MASK) >> PGA11X_CHAN_SHIFT); - settings->u2.gain = (uint8_t)((u2value & PGA11X_GAIN_MASK) >> PGA11X_GAIN_SHIFT); - return OK; -#else - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - uint16_t value; - - spivdbg("Entry\n"); - DEBUGASSERT(handle); - - /* Lock the bus and read the configuration */ - - pga11x_lock(spi); - - /* Select, send the 16-bit PGA11X_CMD_READ command, and de-select. I do - * not know if de-selection between word transfers is required. However, - * it is shown in the timing diagrams for the part. - */ - - SPI_SELECT(spi, SPIDEV_MUX, true); - pga11x_send16(spi, PGA11X_CMD_READ); - SPI_SELECT(spi, SPIDEV_MUX, false); - - /* Re-select, get the returned value, de-select, and unlock */ - - SPI_SELECT(spi, SPIDEV_MUX, true); - value = pga11x_recv16(spi); - SPI_SELECT(spi, SPIDEV_MUX, false); - pga11x_unlock(spi); - - /* Decode the returned value */ - - spivdbg("Returning: %04x\n", value); - settings->channel = (uint8_t)((value & PGA11X_CHAN_MASK) >> PGA11X_CHAN_SHIFT); - settings->gain = (uint8_t)((value & PGA11X_GAIN_MASK) >> PGA11X_GAIN_SHIFT); - return OK; -#endif -} - -/**************************************************************************** - * Name: pga11x_uread - * - * Description: - * Read from one PGA117 amplifier/multiplexer. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_read() reads - * the parts independently. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * pos - Position of the chip in the daisy chain (0 or 1) - * settings - Returned channel and gain settings - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -#ifdef CONFIG_PGA11X_DAISYCHAIN -int pga11x_uread(PGA11X_HANDLE handle, int pos, - FAR struct pga11x_usettings_s *settings) -{ - struct pga11x_settings_s both; - int ret = pga11x_read(handle, &both); - if (ret == OK) - { - if (pos == 0) - { - settings->channel = both.u1.channel; - settings->gain = both.u1.gain; - } - else /* if (pos == 1) */ - { - settings->channel = both.u2.channel; - settings->gain = both.u2.gain; - } - } - - return ret; -} -#endif - -/**************************************************************************** - * Name: pga11x_shutdown - * - * Description: - * Put all PGA11x's in shutdown down mode. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_shutdown() controls - * both chips in the daisy-chain. pga11x_ushutdown() is provided to - * control the parts independently. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -int pga11x_shutdown(PGA11X_HANDLE handle) -{ - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - - spivdbg("Entry\n"); - DEBUGASSERT(handle); - - /* Enter shutdown mode by issuing an SDN_EN command */ - -#ifdef CONFIG_PGA11X_DAISYCHAIN - pga11x_write(spi, PGA11X_CMD_SDN_EN, PGA11X_DCCMD_SDN_EN); -#else - pga11x_write(spi, PGA11X_CMD_SDN_EN); -#endif - return OK; -} - -/**************************************************************************** - * Name: pga11x_ushutdown - * - * Description: - * Put one PGA11x in shutdown down mode. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_ushutdown() is - * provided to shutdown the parts independently. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * pos - Position of the chip in the daisy chain (0 or 1) - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -#ifdef CONFIG_PGA11X_DAISYCHAIN -int pga11x_ushutdown(PGA11X_HANDLE handle, int pos) -{ - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - - spivdbg("Entry\n"); - DEBUGASSERT(handle); - - /* Enter shutdown mode by issuing an SDN_EN command */ - - if (pos == 0) - { - pga11x_write(spi, PGA11X_CMD_SDN_EN, PGA11X_DCCMD_NOOP); - } - else - { - pga11x_write(spi, PGA11X_CMD_NOOP, PGA11X_DCCMD_SDN_EN); - } - - return OK; -} -#endif - -/**************************************************************************** - * Name: pga11x_enable - * - * Description: - * Take all PGA11x's out of shutdown down mode. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_enable() controls - * both chips in the daisy-chain. pga11x_uenable() is provided to - * control the parts independently. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -int pga11x_enable(PGA11X_HANDLE handle) -{ - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - - spivdbg("Entry\n"); - DEBUGASSERT(handle); - - /* Lock the bus and send the shutdown disable command. Shutdown mode is - * cleared (returned to the last valid write configuration) by the SDN_DIS - * command or by any valid Write command - */ - -#ifdef CONFIG_PGA11X_DAISYCHAIN - pga11x_write(spi, PGA11X_CMD_SDN_DIS, PGA11X_DCCMD_SDN_DIS); -#else - pga11x_write(spi, PGA11X_CMD_SDN_DIS); -#endif - return OK; -} - -/**************************************************************************** - * Name: pga11x_uenable - * - * Description: - * Take one PGA11x out of shutdown down mode. - * - * If CONFIG_PGA11X_DAISYCHAIN is defined, then pga11x_uenable() is - * provided to enable the parts independently. - * - * Input Parameters: - * spi - An SPI "bottom half" device driver instance - * pos - Position of the chip in the daisy chain (0 or 1) - * - * Returned Value: - * Zero on sucess; a negated errno value on failure. - * - ****************************************************************************/ - -#ifdef CONFIG_PGA11X_DAISYCHAIN -int pga11x_uenable(PGA11X_HANDLE handle, int pos) -{ - FAR struct spi_dev_s *spi = (FAR struct spi_dev_s *)handle; - - spivdbg("Entry\n"); - DEBUGASSERT(handle); - - /* Enter shutdown mode by issuing an SDN_EN command */ - - if (pos == 0) - { - pga11x_write(spi, PGA11X_CMD_SDN_DIS, PGA11X_DCCMD_NOOP); - } - else - { - pga11x_write(spi, PGA11X_CMD_NOOP, PGA11X_DCCMD_SDN_DIS); - } - - return OK; -} -#endif - -#endif /* CONFIG_ADC && CONFIG_ADC_PGA11X */ - diff --git a/nuttx/drivers/bch/Kconfig b/nuttx/drivers/bch/Kconfig deleted file mode 100644 index ae2bf3130..000000000 --- a/nuttx/drivers/bch/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# diff --git a/nuttx/drivers/bch/Make.defs b/nuttx/drivers/bch/Make.defs deleted file mode 100644 index 78dfbff30..000000000 --- a/nuttx/drivers/bch/Make.defs +++ /dev/null @@ -1,52 +0,0 @@ -############################################################################ -# drivers/bch/Make.defs -# -# Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) -ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) - -# Include BCH driver - -CSRCS += bchlib_setup.c bchlib_teardown.c bchlib_read.c bchlib_write.c \ - bchlib_cache.c bchlib_sem.c bchdev_register.c bchdev_unregister.c \ - bchdev_driver.c - -# Include BCH driver build support - -DEPPATH += --dep-path bch -VPATH += :bch -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)bch} - -endif -endif diff --git a/nuttx/drivers/bch/bch_internal.h b/nuttx/drivers/bch/bch_internal.h deleted file mode 100644 index fb1c64236..000000000 --- a/nuttx/drivers/bch/bch_internal.h +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** - * drivers/bch/bch_internal.h - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __FS_BCH_INTERNAL_H -#define __FS_BCH_INTERNAL_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define bchlib_semgive(d) sem_post(&(d)->sem) /* To match bchlib_semtake */ -#define MAX_OPENCNT (255) /* Limit of uint8_t */ - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -struct bchlib_s -{ - struct inode *inode; /* I-node of the block driver */ - sem_t sem; /* For atomic accesses to this structure */ - size_t nsectors; /* Number of sectors supported by the device */ - size_t sector; /* The current sector in the buffer */ - uint16_t sectsize; /* The size of one sector on the device */ - uint8_t refs; /* Number of references */ - bool dirty; /* Data has been written to the buffer */ - bool readonly; /* true: Only read operations are supported */ - FAR uint8_t *buffer; /* One sector buffer */ -}; - -/**************************************************************************** - * Global Variables - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -EXTERN const struct file_operations bch_fops; - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -EXTERN void bchlib_semtake(FAR struct bchlib_s *bch); -EXTERN int bchlib_flushsector(FAR struct bchlib_s *bch); -EXTERN int bchlib_readsector(FAR struct bchlib_s *bch, size_t sector); - -#undef EXTERN -#if defined(__cplusplus) -} -#endif - -#endif /* __FS_BCH_INTERNAL_H */ diff --git a/nuttx/drivers/bch/bchdev_driver.c b/nuttx/drivers/bch/bchdev_driver.c deleted file mode 100644 index 262a0af46..000000000 --- a/nuttx/drivers/bch/bchdev_driver.c +++ /dev/null @@ -1,255 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchdev_driver.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Compilation Switches - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int bch_open(FAR struct file *filp); -static int bch_close(FAR struct file *filp); -static ssize_t bch_read(FAR struct file *, FAR char *, size_t); -static ssize_t bch_write(FAR struct file *, FAR const char *, size_t); -static int bch_ioctl(FAR struct file *filp, int cmd, unsigned long arg); - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -const struct file_operations bch_fops = -{ - bch_open, /* open */ - bch_close, /* close */ - bch_read, /* read */ - bch_write, /* write */ - 0, /* seek */ - bch_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bch_open - * - * Description: Open the block device - * - ****************************************************************************/ - -static int bch_open(FAR struct file *filp) -{ - FAR struct inode *inode = filp->f_inode; - FAR struct bchlib_s *bch; - - DEBUGASSERT(inode && inode->i_private); - bch = (FAR struct bchlib_s *)inode->i_private; - - /* Increment the reference count */ - - bchlib_semtake(bch); - if (bch->refs == MAX_OPENCNT) - { - return -EMFILE; - } - else - { - bch->refs++; - } - bchlib_semgive(bch); - - return OK; -} - -/**************************************************************************** - * Name: bch_close - * - * Description: close the block device - * - ****************************************************************************/ - -static int bch_close(FAR struct file *filp) -{ - FAR struct inode *inode = filp->f_inode; - FAR struct bchlib_s *bch; - int ret = OK; - - DEBUGASSERT(inode && inode->i_private); - bch = (FAR struct bchlib_s *)inode->i_private; - - /* Flush any dirty pages remaining in the cache */ - - bchlib_semtake(bch); - (void)bchlib_flushsector(bch); - - /* Decrement the reference count (I don't use bchlib_decref() because I - * want the entire close operation to be atomic wrt other driver operations. - */ - - if (bch->refs == 0) - { - ret = -EIO; - } - else - { - bch->refs--; - } - bchlib_semgive(bch); - - return ret; -} - -/**************************************************************************** - * Name:bch_read - ****************************************************************************/ - -static ssize_t bch_read(FAR struct file *filp, FAR char *buffer, size_t len) -{ - FAR struct inode *inode = filp->f_inode; - FAR struct bchlib_s *bch; - int ret; - - DEBUGASSERT(inode && inode->i_private); - bch = (FAR struct bchlib_s *)inode->i_private; - - bchlib_semtake(bch); - ret = bchlib_read(bch, buffer, filp->f_pos, len); - if (ret > 0) - { - filp->f_pos += len; - } - bchlib_semgive(bch); - return ret; -} - -/**************************************************************************** - * Name:bch_write - ****************************************************************************/ - -static ssize_t bch_write(FAR struct file *filp, FAR const char *buffer, size_t len) -{ - FAR struct inode *inode = filp->f_inode; - FAR struct bchlib_s *bch; - int ret = -EACCES; - - DEBUGASSERT(inode && inode->i_private); - bch = (FAR struct bchlib_s *)inode->i_private; - - if (!bch->readonly) - { - bchlib_semtake(bch); - ret = bchlib_write(bch, buffer, filp->f_pos, len); - if (ret > 0) - { - filp->f_pos += len; - } - bchlib_semgive(bch); - } - - return ret; -} - -/**************************************************************************** - * Name: bch_ioctl - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int bch_ioctl(FAR struct file *filp, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filp->f_inode; - FAR struct bchlib_s *bch; - int ret = -ENOTTY; - - DEBUGASSERT(inode && inode->i_private); - bch = (FAR struct bchlib_s *)inode->i_private; - - if (cmd == DIOC_GETPRIV) - { - FAR struct bchlib_s **bchr = (FAR struct bchlib_s **)((uintptr_t)arg); - - bchlib_semtake(bch); - if (!bchr && bch->refs < 255) - { - ret = -EINVAL; - } - else - { - bch->refs++; - *bchr = bch; - } - bchlib_semgive(bch); - } - - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ diff --git a/nuttx/drivers/bch/bchdev_register.c b/nuttx/drivers/bch/bchdev_register.c deleted file mode 100644 index 924977371..000000000 --- a/nuttx/drivers/bch/bchdev_register.c +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchdev_register.c - * - * Copyright (C) 2008-2009, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bchdev_register - * - * Description: - * Setup so that it exports the block driver referenced by 'blkdev' as a - * character device 'chardev' - * - ****************************************************************************/ - -int bchdev_register(FAR const char *blkdev, FAR const char *chardev, - bool readonly) -{ - FAR void *handle; - int ret; - - /* Setup the BCH lib functions */ - - ret = bchlib_setup(blkdev, readonly, &handle); - if (ret < 0) - { - fdbg("bchlib_setup failed: %d\n", -ret); - return ret; - } - - /* Then setup the character device */ - - ret = register_driver(chardev, &bch_fops, 0666, handle); - if (ret < 0) - { - fdbg("register_driver failed: %d\n", -ret); - bchlib_teardown(handle); - handle = NULL; - } - - return ret; -} diff --git a/nuttx/drivers/bch/bchdev_unregister.c b/nuttx/drivers/bch/bchdev_unregister.c deleted file mode 100644 index 8c7360882..000000000 --- a/nuttx/drivers/bch/bchdev_unregister.c +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchdev_unregister.c - * - * Copyright (C) 2008-2009, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bchdev_unregister - * - * Description: - * Unregister character driver access to a block device that was created - * by a previous call to bchdev_register(). - * - ****************************************************************************/ - -int bchdev_unregister(FAR const char *chardev) -{ - FAR struct bchlib_s *bch; - int fd; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!chardev) - { - return -EINVAL; - } -#endif - - /* Open the character driver associated with chardev */ - - fd = open(chardev, O_RDONLY); - if (fd < 0) - { - dbg("Failed to open %s: %d\n", chardev, errno); - return -errno; - } - - /* Get a reference to the internal data structure. On success, we - * will hold a reference count on the state structure. - */ - - ret = ioctl(fd, DIOC_GETPRIV, (unsigned long)((uintptr_t)&bch)); - (void)close(fd); - - if (ret < 0) - { - dbg("ioctl failed: %d\n", errno); - return -errno; - } - - /* Lock out context switches. If there are no other references - * and no context switches, then we can assume that we can safely - * teardown the driver. - */ - - sched_lock(); - - /* Check if the internal structure is non-busy (we hold one reference). */ - - if (bch->refs > 1) - { - ret = -EBUSY; - goto errout_with_lock; - } - - /* Unregister the driver (this cannot suspend or we lose our non-preemptive - * state!). Once the driver is successfully unregistered, we can assume - * we have exclusive access to the state instance. - */ - - ret = unregister_driver(chardev); - if (ret < 0) - { - goto errout_with_lock; - } - - sched_unlock(); - - /* Release the internal structure */ - - bch->refs = 0; - return bchlib_teardown(bch); - -errout_with_lock: - bch->refs--; - sched_unlock(); - return ret; -} diff --git a/nuttx/drivers/bch/bchlib_cache.c b/nuttx/drivers/bch/bchlib_cache.c deleted file mode 100644 index 3b8212a13..000000000 --- a/nuttx/drivers/bch/bchlib_cache.c +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchlib_cache.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bchlib_flushsector - * - * Description: - * Flush the current contents of the sector buffer (if dirty) - * - * Assumptions: - * Caller must assume mutual exclusion - * - ****************************************************************************/ - -int bchlib_flushsector(FAR struct bchlib_s *bch) -{ - FAR struct inode *inode; - ssize_t ret = OK; - - if (bch->dirty) - { - inode = bch->inode; - ret = inode->u.i_bops->write(inode, bch->buffer, bch->sector, 1); - if (ret < 0) - { - fdbg("Write failed: %d\n"); - } - bch->dirty = false; - } - return (int)ret; -} - -/**************************************************************************** - * Name: bchlib_readsector - * - * Description: - * Flush the current contents of the sector buffer (if dirty) - * - * Assumptions: - * Caller must assume mutual exclusion - * - ****************************************************************************/ - -int bchlib_readsector(FAR struct bchlib_s *bch, size_t sector) -{ - FAR struct inode *inode; - ssize_t ret = OK; - - if (bch->sector != sector) - { - inode = bch->inode; - - (void)bchlib_flushsector(bch); - bch->sector = (size_t)-1; - - ret = inode->u.i_bops->read(inode, bch->buffer, sector, 1); - if (ret < 0) - { - fdbg("Read failed: %d\n"); - } - bch->sector = sector; - } - return (int)ret; -} - diff --git a/nuttx/drivers/bch/bchlib_read.c b/nuttx/drivers/bch/bchlib_read.c deleted file mode 100644 index f4fad1096..000000000 --- a/nuttx/drivers/bch/bchlib_read.c +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchlib_read.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bchlib_read - * - * Description: - * Read from the block device set-up by bchlib_setup as if it were a character - * device. - * - ****************************************************************************/ - -ssize_t bchlib_read(FAR void *handle, FAR char *buffer, size_t offset, size_t len) -{ - FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle; - size_t nsectors; - size_t sector; - uint16_t sectoffset; - size_t nbytes; - size_t bytesread; - int ret; - - /* Get rid of this special case right away */ - - if (len < 1) - { - return 0; - } - - /* Convert the file position into a sector number an offset. */ - - sector = offset / bch->sectsize; - sectoffset = offset - sector * bch->sectsize; - - if (sector >= bch->nsectors) - { - /* Return end-of-file */ - - return 0; - } - - /* Read the initial partial sector */ - - bytesread = 0; - if (sectoffset > 0) - { - /* Read the sector into the sector buffer */ - - bchlib_readsector(bch, sector); - - /* Copy the tail end of the sector to the user buffer */ - - if (sectoffset + len > bch->sectsize) - { - nbytes = bch->sectsize - sectoffset; - } - else - { - nbytes = len; - } - - memcpy(buffer, &bch->buffer[sectoffset], nbytes); - - /* Adjust pointers and counts */ - - sectoffset = 0; - sector++; - - if (sector >= bch->nsectors) - { - return nbytes; - } - - bytesread = nbytes; - buffer += nbytes; - len -= nbytes; - } - - /* Then read all of the full sectors following the partial sector directly - * into the user buffer. - */ - - if (len >= bch->sectsize ) - { - nsectors = len / bch->sectsize; - if (sector + nsectors > bch->nsectors) - { - nsectors = bch->nsectors - sector; - } - - ret = bch->inode->u.i_bops->read(bch->inode, (FAR uint8_t *)buffer, - sector, nsectors); - if (ret < 0) - { - fdbg("Read failed: %d\n"); - return ret; - } - - /* Adjust pointers and counts */ - - sectoffset = 0; - sector += nsectors; - - nbytes = nsectors * bch->sectsize; - bytesread += nbytes; - - if (sector >= bch->nsectors) - { - return bytesread; - } - - buffer += nbytes; - len -= nbytes; - } - - /* Then read any partial final sector */ - - if (len > 0) - { - /* Read the sector into the sector buffer */ - - bchlib_readsector(bch, sector); - - /* Copy the head end of the sector to the user buffer */ - - memcpy(buffer, bch->buffer, len); - - /* Adjust counts */ - - bytesread += len; - } - - return bytesread; -} diff --git a/nuttx/drivers/bch/bchlib_sem.c b/nuttx/drivers/bch/bchlib_sem.c deleted file mode 100644 index 1698ed0a5..000000000 --- a/nuttx/drivers/bch/bchlib_sem.c +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchlib_sem.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bch_semtake - ****************************************************************************/ - -void bchlib_semtake(FAR struct bchlib_s *bch) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(&bch->sem) != 0) - { - /* The only case that an error should occur here is if - * the wait was awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} diff --git a/nuttx/drivers/bch/bchlib_setup.c b/nuttx/drivers/bch/bchlib_setup.c deleted file mode 100644 index 1026248b5..000000000 --- a/nuttx/drivers/bch/bchlib_setup.c +++ /dev/null @@ -1,159 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchlib_setup.c - * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bchlib_setup - * - * Description: - * Setup so that the block driver referenced by 'blkdev' can be accessed - * similar to a character device. - * - ****************************************************************************/ - -int bchlib_setup(const char *blkdev, bool readonly, FAR void **handle) -{ - FAR struct bchlib_s *bch; - struct geometry geo; - int ret; - - DEBUGASSERT(blkdev); - - /* Allocate the BCH state structure */ - - bch = (FAR struct bchlib_s*)kzalloc(sizeof(struct bchlib_s)); - if (!bch) - { - fdbg("Failed to allocate BCH structure\n"); - return -ENOMEM; - } - - /* Open the block driver */ - - ret = open_blockdriver(blkdev, readonly ? MS_RDONLY : 0, &bch->inode); - if (ret < 0) - { - fdbg("Failed to open driver %s: %d\n", blkdev, -ret); - goto errout_with_bch; - } - - DEBUGASSERT(bch->inode && bch->inode->u.i_bops && bch->inode->u.i_bops->geometry); - - ret = bch->inode->u.i_bops->geometry(bch->inode, &geo); - if (ret < 0) - { - fdbg("geometry failed: %d\n", -ret); - goto errout_with_bch; - } - - if (!geo.geo_available) - { - fdbg("geometry failed: %d\n", -ret); - ret = -ENODEV; - goto errout_with_bch; - } - - if (!readonly && (!bch->inode->u.i_bops->write || !geo.geo_writeenabled)) - { - fdbg("write access not supported\n"); - ret = -EACCES; - goto errout_with_bch; - } - - /* Save the geometry info and complete initialization of the structure */ - - sem_init(&bch->sem, 0, 1); - bch->nsectors = geo.geo_nsectors; - bch->sectsize = geo.geo_sectorsize; - bch->sector = (size_t)-1; - bch->readonly = readonly; - - /* Allocate the sector I/O buffer */ - - bch->buffer = (FAR uint8_t *)kmalloc(bch->sectsize); - if (!bch->buffer) - { - fdbg("Failed to allocate sector buffer\n"); - ret = -ENOMEM; - goto errout_with_bch; - } - - *handle = bch; - return OK; - -errout_with_bch: - kfree(bch); - return ret; -} diff --git a/nuttx/drivers/bch/bchlib_teardown.c b/nuttx/drivers/bch/bchlib_teardown.c deleted file mode 100644 index 8657c4a69..000000000 --- a/nuttx/drivers/bch/bchlib_teardown.c +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchlib_teardown.c - * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bchlib_teardown - * - * Description: - * Setup so that the block driver referenced by 'blkdev' can be accessed - * similar to a character device. - * - ****************************************************************************/ - -int bchlib_teardown(FAR void *handle) -{ - FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle; - - DEBUGASSERT(handle); - - /* Check that there are not outstanding reference counts on the object */ - - if (bch->refs > 0) - { - return -EBUSY; - } - - /* Flush any pending data to the block driver */ - - bchlib_flushsector(bch); - - /* Close the block driver */ - - (void)close_blockdriver(bch->inode); - - /* Free the BCH state structure */ - - if (bch->buffer) - { - kfree(bch->buffer); - } - - sem_destroy(&bch->sem); - kfree(bch); - return OK; -} - diff --git a/nuttx/drivers/bch/bchlib_write.c b/nuttx/drivers/bch/bchlib_write.c deleted file mode 100644 index 8d7dcf26f..000000000 --- a/nuttx/drivers/bch/bchlib_write.c +++ /dev/null @@ -1,216 +0,0 @@ -/**************************************************************************** - * drivers/bch/bchlib_write.c - * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "bch_internal.h" - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: bchlib_write - * - * Description: - * Write to the block device set-up by bchlib_setup as if it were a character - * device. - * - ****************************************************************************/ - -ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset, size_t len) -{ - FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle; - size_t nsectors; - size_t sector; - uint16_t sectoffset; - size_t nbytes; - size_t byteswritten; - int ret; - - /* Get rid of this special case right away */ - - if (len < 1) - { - return 0; - } - - /* Convert the file position into a sector number an offset. */ - - sector = offset / bch->sectsize; - sectoffset = offset - sector * bch->sectsize; - - if (sector >= bch->nsectors) - { - return -EFBIG; - } - - /* Write the initial partial sector */ - - byteswritten = 0; - if (sectoffset > 0) - { - /* Read the full sector into the sector buffer */ - - bchlib_readsector(bch, sector); - - /* Copy the tail end of the sector from the user buffer */ - - if (sectoffset + len > bch->sectsize) - { - nbytes = bch->sectsize - sectoffset; - } - else - { - nbytes = len; - } - - memcpy(&bch->buffer[sectoffset], buffer, nbytes); - bch->dirty = true; - - /* Adjust pointers and counts */ - - sectoffset = 0; - sector++; - - if (sector >= bch->nsectors) - { - return nbytes; - } - - byteswritten = nbytes; - buffer += nbytes; - len -= nbytes; - } - - /* Then write all of the full sectors following the partial sector - * directly from the user buffer. - */ - - if (len >= bch->sectsize ) - { - nsectors = len / bch->sectsize; - if (sector + nsectors > bch->nsectors) - { - nsectors = bch->nsectors - sector; - } - - /* Write the contiguous sectors */ - - ret = bch->inode->u.i_bops->write(bch->inode, (FAR uint8_t *)buffer, - sector, nsectors); - if (ret < 0) - { - fdbg("Write failed: %d\n", ret); - return ret; - } - - /* Adjust pointers and counts */ - - sectoffset = 0; - sector += nsectors; - - nbytes = nsectors * bch->sectsize; - byteswritten += nbytes; - - if (sector >= bch->nsectors) - { - return byteswritten; - } - - buffer += nbytes; - len -= nbytes; - } - - /* Then write any partial final sector */ - - if (len > 0) - { - /* Read the sector into the sector buffer */ - - bchlib_readsector(bch, sector); - - /* Copy the head end of the sector from the user buffer */ - - memcpy(bch->buffer, buffer, len); - bch->dirty = true; - - /* Adjust counts */ - - byteswritten += len; - } - - /* Finally, flush any cached writes to the device as well */ - - ret = bchlib_flushsector(bch); - if (ret < 0) - { - fdbg("Flush failed: %d\n", ret); - return ret; - } - - return byteswritten; -} - diff --git a/nuttx/drivers/can.c b/nuttx/drivers/can.c deleted file mode 100644 index 2c1567781..000000000 --- a/nuttx/drivers/can.c +++ /dev/null @@ -1,845 +0,0 @@ -/**************************************************************************** - * drivers/can.c - * - * Copyright (C) 2008-2009, 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef CONFIG_CAN - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Debug ********************************************************************/ -/* Non-standard debug that may be enabled just for testing CAN */ - -#ifdef CONFIG_DEBUG_CAN -# define candbg dbg -# define canvdbg vdbg -# define canlldbg lldbg -# define canllvdbg llvdbg -#else -# define candbg(x...) -# define canvdbg(x...) -# define canlldbg(x...) -# define canllvdbg(x...) -#endif - -/* Timing Definitions *******************************************************/ - -#define HALF_SECOND_MSEC 500 -#define HALF_SECOND_USEC 500000L - -/**************************************************************************** - * Private Type Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int can_open(FAR struct file *filep); -static int can_close(FAR struct file *filep); -static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen); -static int can_xmit(FAR struct can_dev_s *dev); -static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static inline ssize_t can_rtrread(FAR struct can_dev_s *dev, FAR struct canioctl_rtr_s *rtr); -static int can_ioctl(FAR struct file *filep, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations g_canops = -{ - can_open, /* open */ - can_close, /* close */ - can_read, /* read */ - can_write, /* write */ - 0, /* seek */ - can_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/************************************************************************************ - * Name: can_open - * - * Description: - * This function is called whenever the CAN device is opened. - * - ************************************************************************************/ - -static int can_open(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct can_dev_s *dev = inode->i_private; - uint8_t tmp; - int ret = OK; - - canvdbg("ocount: %d\n", dev->cd_ocount); - - /* If the port is the middle of closing, wait until the close is finished */ - - if (sem_wait(&dev->cd_closesem) != OK) - { - ret = -errno; - } - else - { - /* Increment the count of references to the device. If this the first - * time that the driver has been opened for this device, then initialize - * the device. - */ - - tmp = dev->cd_ocount + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - } - else - { - /* Check if this is the first time that the driver has been opened. */ - - if (tmp == 1) - { - /* Yes.. perform one time hardware initialization. */ - - irqstate_t flags = irqsave(); - ret = dev_setup(dev); - if (ret == OK) - { - /* Mark the FIFOs empty */ - - dev->cd_xmit.tx_head = 0; - dev->cd_xmit.tx_queue = 0; - dev->cd_xmit.tx_tail = 0; - dev->cd_recv.rx_head = 0; - dev->cd_recv.rx_tail = 0; - - /* Finally, Enable the CAN RX interrupt */ - - dev_rxint(dev, true); - - /* Save the new open count on success */ - - dev->cd_ocount = tmp; - } - irqrestore(flags); - } - } - sem_post(&dev->cd_closesem); - } - return ret; -} - -/************************************************************************************ - * Name: can_close - * - * Description: - * This routine is called when the CAN device is closed. - * It waits for the last remaining data to be sent. - * - ************************************************************************************/ - -static int can_close(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct can_dev_s *dev = inode->i_private; - irqstate_t flags; - int ret = OK; - - canvdbg("ocount: %d\n", dev->cd_ocount); - - if (sem_wait(&dev->cd_closesem) != OK) - { - ret = -errno; - } - else - { - /* Decrement the references to the driver. If the reference count will - * decrement to 0, then uninitialize the driver. - */ - - if (dev->cd_ocount > 1) - { - dev->cd_ocount--; - sem_post(&dev->cd_closesem); - } - else - { - /* There are no more references to the port */ - - dev->cd_ocount = 0; - - /* Stop accepting input */ - - dev_rxint(dev, false); - - /* Now we wait for the transmit FIFO to clear */ - - while (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail) - { -#ifndef CONFIG_DISABLE_SIGNALS - usleep(HALF_SECOND_USEC); -#else - up_mdelay(HALF_SECOND_MSEC); -#endif - } - - /* And wait for the TX hardware FIFO to drain */ - - while (!dev_txempty(dev)) - { -#ifndef CONFIG_DISABLE_SIGNALS - usleep(HALF_SECOND_USEC); -#else - up_mdelay(HALF_SECOND_MSEC); -#endif - } - - /* Free the IRQ and disable the CAN device */ - - flags = irqsave(); /* Disable interrupts */ - dev_shutdown(dev); /* Disable the CAN */ - irqrestore(flags); - - sem_post(&dev->cd_closesem); - } - } - return ret; -} - -/************************************************************************************ - * Name: can_read - * - * Description: - * Read standard CAN messages - * - ************************************************************************************/ - -static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct can_dev_s *dev = inode->i_private; - size_t nread; - irqstate_t flags; - int ret = 0; - - canvdbg("buflen: %d\n", buflen); - - /* The caller must provide enough memory to catch the smallest possible message - * This is not a system error condition, but we won't permit it, Hence we return 0. - */ - - if (buflen >= CAN_MSGLEN(0)) - { - /* Interrupts must be disabled while accessing the cd_recv FIFO */ - - flags = irqsave(); - while (dev->cd_recv.rx_head == dev->cd_recv.rx_tail) - { - /* The receive FIFO is empty -- was non-blocking mode selected? */ - - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto return_with_irqdisabled; - } - - /* Wait for a message to be received */ - - ret = sem_wait(&dev->cd_recv.rx_sem); - if (ret < 0) - { - ret = -errno; - goto return_with_irqdisabled; - } - } - - /* The cd_recv FIFO is not empty. Copy all buffered data that will fit - * in the user buffer. - */ - - nread = 0; - do - { - /* Will the next message in the FIFO fit into the user buffer? */ - - FAR struct can_msg_s *msg = &dev->cd_recv.rx_buffer[dev->cd_recv.rx_head]; - int msglen = CAN_MSGLEN(msg->cm_hdr.ch_dlc); - - if (nread + msglen > buflen) - { - break; - } - - /* Copy the message to the user buffer */ - - memcpy(&buffer[nread], msg, msglen); - nread += msglen; - - /* Increment the head of the circular message buffer */ - - if (++dev->cd_recv.rx_head >= CONFIG_CAN_FIFOSIZE) - { - dev->cd_recv.rx_head = 0; - } - } - while (dev->cd_recv.rx_head != dev->cd_recv.rx_tail); - - /* All on the messages have bee transferred. Return the number of bytes - * that were read. - */ - - ret = nread; - -return_with_irqdisabled: - irqrestore(flags); - } - return ret; -} - -/************************************************************************************ - * Name: can_xmit - * - * Description: - * Send the message at the head of the cd_xmit FIFO - * - * Assumptions: - * Called with interrupts disabled - * - ************************************************************************************/ - -static int can_xmit(FAR struct can_dev_s *dev) -{ - int tmpndx; - int ret = -EBUSY; - - canllvdbg("xmit head: %d queue: %d tail: %d\n", - dev->cd_xmit.tx_head, dev->cd_xmit.tx_queue, dev->cd_xmit.tx_tail); - - /* If there is nothing to send, then just disable interrupts and return */ - - if (dev->cd_xmit.tx_head == dev->cd_xmit.tx_tail) - { - DEBUGASSERT(dev->cd_xmit.tx_queue == dev->cd_xmit.tx_head); - dev_txint(dev, false); - return -EIO; - } - - /* Check if we have already queued all of the data in the TX fifo. - * - * tx_tail: Incremented in can_write each time a message is queued in the FIFO - * tx_head: Incremented in can_txdone each time a message completes - * tx_queue: Incremented each time that a message is sent to the hardware. - * - * Logically (ignoring buffer wrap-around): tx_head <= tx_queue <= tx_tail - * tx_head == tx_queue == tx_tail means that the FIFO is empty - * tx_head < tx_queue == tx_tail means that all data has been queued, but - * we are still waiting for transmissions to complete. - */ - - while (dev->cd_xmit.tx_queue != dev->cd_xmit.tx_tail && dev_txready(dev)) - { - /* No.. The fifo should not be empty in this case */ - - DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail); - - /* Increment the FIFO queue index before sending (because dev_send() - * might call can_txdone(). - */ - - tmpndx = dev->cd_xmit.tx_queue; - if (++dev->cd_xmit.tx_queue >= CONFIG_CAN_FIFOSIZE) - { - dev->cd_xmit.tx_queue = 0; - } - - /* Send the next message at the FIFO queue index */ - - ret = dev_send(dev, &dev->cd_xmit.tx_buffer[tmpndx]); - if (ret != OK) - { - candbg("dev_send failed: %d\n", ret); - break; - } - } - - /* Make sure that TX interrupts are enabled */ - - dev_txint(dev, true); - return ret; -} - -/************************************************************************************ - * Name: can_write - ************************************************************************************/ - -static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct can_dev_s *dev = inode->i_private; - FAR struct can_txfifo_s *fifo = &dev->cd_xmit; - FAR struct can_msg_s *msg; - bool inactive; - ssize_t nsent = 0; - irqstate_t flags; - int nexttail; - int msglen; - int ret = 0; - - canvdbg("buflen: %d\n", buflen); - - /* Interrupts must disabled throughout the following */ - - flags = irqsave(); - - /* Check if the TX is inactive when we started. In certain race conditionas, there - * may be a pending interrupt to kick things back off, but we will here that there - * is not. That the hardware is IDLE and will need to be kick-started. - */ - - inactive = dev_txempty(dev); - - /* Add the messages to the FIFO. Ignore any trailing messages that are - * shorter than the minimum. - */ - - while ((buflen - nsent) >= CAN_MSGLEN(0)) - { - /* Check if adding this new message would over-run the drivers ability to enqueue - * xmit data. - */ - - nexttail = fifo->tx_tail + 1; - if (nexttail >= CONFIG_CAN_FIFOSIZE) - { - nexttail = 0; - } - - /* If the XMIT fifo becomes full, then wait for space to become available */ - - while (nexttail == fifo->tx_head) - { - /* The transmit FIFO is full -- was non-blocking mode selected? */ - - if (filep->f_oflags & O_NONBLOCK) - { - if (nsent == 0) - { - ret = -EAGAIN; - } - else - { - ret = nsent; - } - goto return_with_irqdisabled; - } - - /* If the TX hardware was inactive when we started, then we will have - * start the XMIT sequence generate the TX done interrrupts needed - * to clear the FIFO. - */ - - if (inactive) - { - can_xmit(dev); - } - - /* Wait for a message to be sent */ - - do - { - DEBUGASSERT(dev->cd_ntxwaiters < 255); - dev->cd_ntxwaiters++; - ret = sem_wait(&fifo->tx_sem); - dev->cd_ntxwaiters--; - - if (ret < 0 && errno != EINTR) - { - ret = -errno; - goto return_with_irqdisabled; - } - } - while (ret < 0); - - /* Re-check the FIFO state */ - - inactive = dev_txempty(dev); - } - - /* We get here if there is space at the end of the FIFO. Add the new - * CAN message at the tail of the FIFO. - */ - - msg = (FAR struct can_msg_s *)&buffer[nsent]; - msglen = CAN_MSGLEN(msg->cm_hdr.ch_dlc); - memcpy(&fifo->tx_buffer[fifo->tx_tail], msg, msglen); - - /* Increment the tail of the circular buffer */ - - fifo->tx_tail = nexttail; - - /* Increment the number of bytes that were sent */ - - nsent += msglen; - } - - /* We get here after all messages have been added to the FIFO. Check if - * we need to kick of the XMIT sequence. - */ - - if (inactive) - { - can_xmit(dev); - } - - /* Return the number of bytes that were sent */ - - ret = nsent; - -return_with_irqdisabled: - irqrestore(flags); - return ret; -} - -/************************************************************************************ - * Name: can_rtrread - * - * Description: - * Read RTR messages. The RTR message is a special message -- it is an outgoing - * message that says "Please re-transmit the message with the same identifier as - * this message. So the RTR read is really a send-wait-receive operation. - * - ************************************************************************************/ - -static inline ssize_t can_rtrread(FAR struct can_dev_s *dev, FAR struct canioctl_rtr_s *rtr) -{ - FAR struct can_rtrwait_s *wait = NULL; - irqstate_t flags; - int i; - int ret = -ENOMEM; - - /* Disable interrupts through this operation */ - - flags = irqsave(); - - /* Find an avaiable slot in the pending RTR list */ - - for (i = 0; i < CONFIG_CAN_NPENDINGRTR; i++) - { - FAR struct can_rtrwait_s *tmp = &dev->cd_rtr[i]; - if (!rtr->ci_msg) - { - tmp->cr_id = rtr->ci_id; - tmp->cr_msg = rtr->ci_msg; - dev->cd_npendrtr++; - wait = tmp; - break; - } - } - - if (wait) - { - /* Send the remote transmission request */ - - ret = dev_remoterequest(dev, wait->cr_id); - if (ret == OK) - { - /* Then wait for the response */ - - ret = sem_wait(&wait->cr_sem); - } - } - irqrestore(flags); - return ret; -} - -/************************************************************************************ - * Name: can_ioctl - ************************************************************************************/ - -static int can_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct can_dev_s *dev = inode->i_private; - int ret = OK; - - canvdbg("cmd: %d arg: %ld\n", cmd, arg); - - /* Handle built-in ioctl commands */ - - switch (cmd) - { - /* CANIOCTL_RTR: Send the remote transmission request and wait for the response. - * Argument is a reference to struct canioctl_rtr_s (casting to uintptr_t first - * eliminates complaints on some architectures where the sizeof long is different - * from the size of a pointer). - */ - - case CANIOCTL_RTR: - ret = can_rtrread(dev, (struct canioctl_rtr_s*)((uintptr_t)arg)); - break; - - /* Not a "built-in" ioctl command.. perhaps it is unique to this device driver */ - - default: - ret = dev_ioctl(dev, cmd, arg); - break; - } - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/************************************************************************************ - * Name: can_register - * - * Description: - * Register serial console and serial ports. - * - ************************************************************************************/ - -int can_register(FAR const char *path, FAR struct can_dev_s *dev) -{ - int i; - - /* Initialize the CAN device structure */ - - dev->cd_ocount = 0; - - sem_init(&dev->cd_xmit.tx_sem, 0, 0); - sem_init(&dev->cd_recv.rx_sem, 0, 0); - sem_init(&dev->cd_closesem, 0, 1); - - for (i = 0; i < CONFIG_CAN_NPENDINGRTR; i++) - { - sem_init(&dev->cd_rtr[i].cr_sem, 0, 0); - dev->cd_rtr[i].cr_msg = NULL; - dev->cd_npendrtr--; - } - - /* Initialize/reset the CAN hardware */ - - dev_reset(dev); - - /* Register the CAN device */ - - canvdbg("Registering %s\n", path); - return register_driver(path, &g_canops, 0666, dev); -} - -/************************************************************************************ - * Name: can_receive - * - * Description: - * Called from the CAN interrupt handler when new read data is available - * - * Parameters: - * dev - CAN driver state structure - * hdr - CAN message header - * data - CAN message data (if DLC > 0) - * - * Assumptions: - * CAN interrupts are disabled. - * - ************************************************************************************/ - -int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr, FAR uint8_t *data) -{ - FAR struct can_rxfifo_s *fifo = &dev->cd_recv; - FAR uint8_t *dest; - int nexttail; - int err = -ENOMEM; - int i; - - canllvdbg("ID: %d DLC: %d\n", hdr->ch_id, hdr->ch_dlc); - - /* Check if adding this new message would over-run the drivers ability to enqueue - * read data. - */ - - nexttail = fifo->rx_tail + 1; - if (nexttail >= CONFIG_CAN_FIFOSIZE) - { - nexttail = 0; - } - - /* First, check if this response matches any RTR response that we may be waiting for */ - - if (dev->cd_npendrtr > 0) - { - /* There are pending RTR requests -- search the lists of requests - * and see any any matches this new message. - */ - - for (i = 0; i < CONFIG_CAN_NPENDINGRTR; i++) - { - FAR struct can_rtrwait_s *rtr = &dev->cd_rtr[i]; - FAR struct can_msg_s *msg = rtr->cr_msg; - - /* Check if the entry is valid and if the ID matches. A valid entry has - * a non-NULL receiving address - */ - - if (msg && hdr->ch_id == rtr->cr_id) - { - /* We have the response... copy the data to the user's buffer */ - - memcpy(&msg->cm_hdr, hdr, sizeof(struct can_hdr_s)); - for (i = 0, dest = msg->cm_data; i < hdr->ch_dlc; i++) - { - *dest++ = *data++; - } - - /* Mark the entry unused */ - - rtr->cr_msg = NULL; - - /* And restart the waiting thread */ - - sem_post(&rtr->cr_sem); - } - } - } - - /* Refuse the new data if the FIFO is full */ - - if (nexttail != fifo->rx_head) - { - /* Add the new, decoded CAN message at the tail of the FIFO */ - - memcpy(&fifo->rx_buffer[fifo->rx_tail].cm_hdr, hdr, sizeof(struct can_hdr_s)); - for (i = 0, dest = fifo->rx_buffer[fifo->rx_tail].cm_data; i < hdr->ch_dlc; i++) - { - *dest++ = *data++; - } - - /* Increment the tail of the circular buffer */ - - fifo->rx_tail = nexttail; - - /* The increment the counting semaphore. The maximum value should be - * CONFIG_CAN_FIFOSIZE -- one possible count for each allocated message buffer. - */ - - sem_post(&fifo->rx_sem); - err = OK; - } - return err; -} - -/************************************************************************************ - * Name: can_txdone - * - * Description: - * Called from the CAN interrupt handler at the completion of a send operation. - * - * Parameters: - * dev - The specific CAN device - * hdr - The 16-bit CAN header - * data - An array contain the CAN data. - * - * Return: - * OK on success; a negated errno on failure. - * - ************************************************************************************/ - -int can_txdone(FAR struct can_dev_s *dev) -{ - int ret = -ENOENT; - - canllvdbg("xmit head: %d queue: %d tail: %d\n", - dev->cd_xmit.tx_head, dev->cd_xmit.tx_queue, dev->cd_xmit.tx_tail); - - /* Verify that the xmit FIFO is not empty */ - - if (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail) - { - DEBUGASSERT(dev->cd_xmit.tx_head != dev->cd_xmit.tx_queue); - - /* Remove the message at the head of the xmit FIFO */ - - if (++dev->cd_xmit.tx_head >= CONFIG_CAN_FIFOSIZE) - { - dev->cd_xmit.tx_head = 0; - } - - /* Send the next message in the FIFO */ - - ret = can_xmit(dev); - - /* Are there any threads waiting for space in the TX FIFO? */ - - if (ret == OK && dev->cd_ntxwaiters > 0) - { - /* Yes.. Inform them that new xmit space is available */ - - ret = sem_post(&dev->cd_xmit.tx_sem); - } - } - return ret; -} - -#endif /* CONFIG_CAN */ diff --git a/nuttx/drivers/dev_null.c b/nuttx/drivers/dev_null.c deleted file mode 100644 index c70370e1e..000000000 --- a/nuttx/drivers/dev_null.c +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** - * drivers/dev_null.c - * - * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static ssize_t devnull_read(FAR struct file *, FAR char *, size_t); -static ssize_t devnull_write(FAR struct file *, FAR const char *, size_t); -#ifndef CONFIG_DISABLE_POLL -static int devnull_poll(FAR struct file *filp, FAR struct pollfd *fds, - bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations devnull_fops = -{ - 0, /* open */ - 0, /* close */ - devnull_read, /* read */ - devnull_write, /* write */ - 0, /* seek */ - 0 /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , devnull_poll /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: devnull_read - ****************************************************************************/ - -static ssize_t devnull_read(FAR struct file *filp, FAR char *buffer, size_t len) -{ - return 0; /* Return EOF */ -} - -/**************************************************************************** - * Name: devnull_write - ****************************************************************************/ - -static ssize_t devnull_write(FAR struct file *filp, FAR const char *buffer, size_t len) -{ - return len; /* Say that everything was written */ -} - -/**************************************************************************** - * Name: devnull_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int devnull_poll(FAR struct file *filp, FAR struct pollfd *fds, - bool setup) -{ - if (setup) - { - fds->revents |= (fds->events & (POLLIN|POLLOUT)); - if (fds->revents != 0) - { - sem_post(fds->sem); - } - } - - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: devnull_register - * - * Description: - * Register /dev/null - * - ****************************************************************************/ - -void devnull_register(void) -{ - (void)register_driver("/dev/null", &devnull_fops, 0666, NULL); -} diff --git a/nuttx/drivers/dev_zero.c b/nuttx/drivers/dev_zero.c deleted file mode 100644 index 5435f80ea..000000000 --- a/nuttx/drivers/dev_zero.c +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** - * drivers/dev_null.c - * - * Copyright (C) 2008-2009, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static ssize_t devzero_read(FAR struct file *, FAR char *, size_t); -static ssize_t devzero_write(FAR struct file *, FAR const char *, size_t); -#ifndef CONFIG_DISABLE_POLL -static int devzero_poll(FAR struct file *filp, FAR struct pollfd *fds, - bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations devzero_fops = -{ - 0, /* open */ - 0, /* close */ - devzero_read, /* read */ - devzero_write, /* write */ - 0, /* seek */ - 0 /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , devzero_poll /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: devzero_read - ****************************************************************************/ - -static ssize_t devzero_read(FAR struct file *filp, FAR char *buffer, size_t len) -{ - memset(buffer, 0, len); - return len; -} - -/**************************************************************************** - * Name: devzero_write - ****************************************************************************/ - -static ssize_t devzero_write(FAR struct file *filp, FAR const char *buffer, size_t len) -{ - return len; -} - -/**************************************************************************** - * Name: devzero_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int devzero_poll(FAR struct file *filp, FAR struct pollfd *fds, - bool setup) -{ - if (setup) - { - fds->revents |= (fds->events & (POLLIN|POLLOUT)); - if (fds->revents != 0) - { - sem_post(fds->sem); - } - } - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: devzero_register - * - * Description: - * Register /dev/zero - * - ****************************************************************************/ - -void devzero_register(void) -{ - (void)register_driver("/dev/zero", &devzero_fops, 0666, NULL); -} diff --git a/nuttx/drivers/input/Kconfig b/nuttx/drivers/input/Kconfig deleted file mode 100644 index 6da3a9f39..000000000 --- a/nuttx/drivers/input/Kconfig +++ /dev/null @@ -1,228 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config INPUT_TSC2007 - bool "TI TSC2007 touchscreen controller" - default n - select I2C - ---help--- - Enable support for the TI TSC2007 touchscreen controller - -if INPUT_TSC2007 - -config TSC2007_8BIT - bool "8-bit Conversions" - default n - ---help--- - Use faster, but less accurate, 8-bit conversions. Default: 12-bit conversions. - -config TSC2007_MULTIPLE - bool "Multiple TSC2007 Devices" - default n - ---help--- - Can be defined to support multiple TSC2007 devices on board. - -config TSC2007_NPOLLWAITERS - int "Number poll waiters" - default 4 - depends on !DISABLE_POLL - ---help--- - Maximum number of threads that can be waiting on poll() - -endif - -config INPUT_ADS7843E - bool "TI ADS7843/TSC2046 touchscreen controller" - default n - select SPI - ---help--- - Enable support for the TI/Burr-Brown ADS7842 touchscreen controller. I believe - that driver should be compatibile with the TI/Burr-Brown TSC2046 and XPT2046 - touchscreen controllers as well. - -if INPUT_ADS7843E - -config ADS7843E_MULTIPLE - bool "Multiple ADS7843E Devices" - default n - ---help--- - Can be defined to support multiple ADS7843E devices on board. - -config ADS7843E_NPOLLWAITERS - int "Number poll waiters" - default 4 - depends on !DISABLE_POLL - ---help--- - Maximum number of threads that can be waiting on poll() - -config ADS7843E_SPIMODE - int "SPI mode" - default 0 - range 0,3 - ---help--- - Controls the SPI mode. The device should work in mode 0, but sometimes - you need to experiment. - -config ADS7843E_FREQUENCY - int "SPI frequency" - default 100000 - ---help--- - Define to use a different SPI bus frequency. - -config ADS7843E_SWAPXY - bool "Swap X/Y" - default n - ---help--- - Reverse the meaning of X and Y to handle different LCD orientations. - -config ADS7843E_THRESHX - int "X threshold" - default 12 - ---help--- - New touch positions will only be reported when the X or Y data changes by these - thresholds. This trades reduces data rate for some loss in dragging accuracy. For - 12-bit values so the raw ranges are 0-4095. So for example, if your display is - 320x240, then THRESHX=13 and THRESHY=17 would correspond to one pixel. Default: 12 - -config ADS7843E_THRESHY - int "Y threshold" - default 12 - ---help--- - New touch positions will only be reported when the X or Y data changes by these - thresholds. This trades reduces data rate for some loss in dragging accuracy. For - 12-bit values so the raw ranges are 0-4095. So for example, if your display is - 320x240, then THRESHX=13 and THRESHY=17 would correspond to one pixel. Default: 12 - -endif - -config INPUT_STMPE811 - bool "STMicro STMPE811 Driver" - default n - ---help--- - Enables support for the STMPE811 driver - -if INPUT_STMPE811 - -choice - prompt "STMPE Interface" - default STMPE811_I2C - -config STMPE811_SPI - bool "SPI Interface" - select SPI - ---help--- - Enables support for the SPI interface (not currently supported) - -config STMPE811_I2C - bool "STMPE811 I2C Interface" - select I2C - ---help--- - Enables support for the I2C interface - -endchoice - -config STMPE811_ACTIVELOW - bool "Active Low Interrupt" - default n - ---help--- - The STMPE811 interrupt is provided by a discrete input (usually a - GPIO interrupt on most MCU architectures). This setting determines - whether the interrupt is active high (or rising edge triggered) or - active low (or falling edge triggered). Default: Active - high/rising edge. - -config STMPE811_EDGE - bool "Edge triggered Interrupt" - default n - ---help--- - The STMPE811 interrupt is provided by a discrete input (usually a - GPIO interrupt on most MCU architectures). This setting determines - whether the interrupt is edge or level triggered. Default: Level - triggered. - -config STMPE811_MULTIPLE - bool "Multiple STMPE811 Devices" - default n - ---help--- - Can be defined to support multiple STMPE811 devices on board. - -config STMPE811_NPOLLWAITERS - int "Number poll waiters" - default 4 - depends on !DISABLE_POLL - ---help--- - Maximum number of threads that can be waiting on poll() - -config STMPE811_TSC_DISABLE - bool "Disable STMPE811 Touchscreen Support" - default n - ---help--- - Disable driver touchscreen functionality. - -config STMPE811_SWAPXY - bool "Swap X/Y" - default n - depends on !STMPE811_TSC_DISABLE - ---help--- - Reverse the meaning of X and Y to handle different LCD orientations. - -config STMPE811_THRESHX - int "X threshold" - default 12 - depends on !STMPE811_TSC_DISABLE - ---help--- - STMPE811 touchscreen data comes in a a very high rate. New touch positions - will only be reported when the X or Y data changes by these thresholds. - This trades reduces data rate for some loss in dragging accuracy. The - STMPE811 is configure for 12-bit values so the raw ranges are 0-4095. So - for example, if your display is 320x240, then THRESHX=13 and THRESHY=17 - would correspond to one pixel. Default: 12 - -config STMPE811_THRESHY - int "Y threshold" - default 12 - depends on !STMPE811_TSC_DISABLE - ---help--- - STMPE811 touchscreen data comes in a a very high rate. New touch positions - will only be reported when the X or Y data changes by these thresholds. - This trades reduces data rate for some loss in dragging accuracy. The - STMPE811 is configure for 12-bit values so the raw ranges are 0-4095. So - for example, if your display is 320x240, then THRESHX=13 and THRESHY=17 - would correspond to one pixel. Default: 12 - -config STMPE811_ADC_DISABLE - bool "Disable STMPE811 ADC Support" - default y - ---help--- - Disable driver ADC functionality. - -config STMPE811_GPIO_DISABLE - bool "Disable STMPE811 GPIO Support" - default y - ---help--- - Disable driver GPIO functionality. - -config STMPE811_GPIOINT_DISABLE - bool "Disable STMPE811 GPIO Interrupt Support" - default y - depends on !STMPE811_GPIO_DISABLE - ---help--- - Disable driver GPIO interrupt functionlality (ignored if GPIO functionality is - disabled). - -config STMPE811_TEMP_DISABLE - bool "Disable STMPE811 Temperature Sensor Support" - default y - ---help--- - Disable driver temperature sensor functionality. - -config STMPE811_REGDEBUG - bool "Enable Register-Level STMPE811 Debug" - default n - depends on DEBUG - ---help--- - Enable very low register-level debug output. - -endif diff --git a/nuttx/drivers/input/Make.defs b/nuttx/drivers/input/Make.defs deleted file mode 100644 index 10e6db62f..000000000 --- a/nuttx/drivers/input/Make.defs +++ /dev/null @@ -1,76 +0,0 @@ -############################################################################ -# drivers/input/Make.defs -# -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Don't build anything if there is no NX support for input devices - -ifeq ($(CONFIG_INPUT),y) - -# Include the selected touchscreen drivers - -ifeq ($(CONFIG_INPUT_TSC2007),y) - CSRCS += tsc2007.c -endif - -ifeq ($(CONFIG_INPUT_ADS7843E),y) - CSRCS += ads7843e.c -endif - -ifeq ($(CONFIG_INPUT_MAX11802),y) - CSRCS += max11802.c -endif - -ifeq ($(CONFIG_INPUT_STMPE811),y) - CSRCS += stmpe811_base.c -ifneq ($(CONFIG_INPUT_STMPE811_TSC_DISABLE),y) - CSRCS += stmpe811_tsc.c -endif -ifneq ($(CONFIG_INPUT_STMPE811_GPIO_DISABLE),y) - CSRCS += stmpe811_gpio.c -endif -ifneq ($(CONFIG_INPUT_STMPE811_ADC_DISABLE),y) - CSRCS += stmpe811_adc.c -endif -ifneq ($(CONFIG_INPUT_STMPE811_TEMP_DISABLE),y) - CSRCS += stmpe811_temp.c -endif -endif - -# Include input device driver build support - -DEPPATH += --dep-path input -VPATH += :input -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)input} -endif - diff --git a/nuttx/drivers/input/ads7843e.c b/nuttx/drivers/input/ads7843e.c deleted file mode 100644 index 06969e6d2..000000000 --- a/nuttx/drivers/input/ads7843e.c +++ /dev/null @@ -1,1283 +0,0 @@ -/**************************************************************************** - * drivers/input/ads7843e.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * Diego Sanchez - * - * References: - * "Touch Screen Controller, ADS7843," Burr-Brown Products from Texas - * Instruments, SBAS090B, September 2000, Revised May 2002" - * - * See also: - * "Low Voltage I/O Touch Screen Controller, TSC2046," Burr-Brown Products - * from Texas Instruments, SBAS265F, October 2002, Revised August 2007. - * - * "XPT2046 Data Sheet," Shenzhen XPTek Technology Co., Ltd, 2007 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "ads7843e.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* This is a value for the threshold that guantees a big difference on the - * first pendown (but can't overflow). - */ - -#define INVALID_THRESHOLD 0x1000 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ads7843e_configspi(FAR struct spi_dev_s *spi); -# define ads7843e_lock(spi) -# define ads7843e_unlock(spi) -#else -# define ads7843e_configspi(spi); -static void ads7843e_lock(FAR struct spi_dev_s *spi); -static void ads7843e_unlock(FAR struct spi_dev_s *spi); -#endif - -static inline void ads7843e_waitbusy(FAR struct ads7843e_dev_s *priv); -static uint16_t ads7843e_sendcmd(FAR struct ads7843e_dev_s *priv, uint8_t cmd); - -/* Interrupts and data sampling */ - -static void ads7843e_notify(FAR struct ads7843e_dev_s *priv); -static int ads7843e_sample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample); -static int ads7843e_waitsample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample); -static void ads7843e_worker(FAR void *arg); -static int ads7843e_interrupt(int irq, FAR void *context); - -/* Character driver methods */ - -static int ads7843e_open(FAR struct file *filep); -static int ads7843e_close(FAR struct file *filep); -static ssize_t ads7843e_read(FAR struct file *filep, FAR char *buffer, size_t len); -static int ads7843e_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int ads7843e_poll(FAR struct file *filep, struct pollfd *fds, bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This the the vtable that supports the character driver interface */ - -static const struct file_operations ads7843e_fops = -{ - ads7843e_open, /* open */ - ads7843e_close, /* close */ - ads7843e_read, /* read */ - 0, /* write */ - 0, /* seek */ - ads7843e_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , ads7843e_poll /* poll */ -#endif -}; - -/* If only a single ADS7843E device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_ADS7843E_MULTIPLE -static struct ads7843e_dev_s g_ads7843e; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct ads7843e_dev_s *g_ads7843elist; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: ads7843e_lock - * - * Description: - * Lock the SPI bus and re-configure as necessary. This function must be - * to assure: (1) exclusive access to the SPI bus, and (2) to assure that - * the shared bus is properly configured for the touchscreen controller. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void ads7843e_lock(FAR struct spi_dev_s *spi) -{ - /* Lock the SPI bus because there are multiple devices competing for the - * SPI bus - */ - - (void)SPI_LOCK(spi, true); - - /* We have the lock. Now make sure that the SPI bus is configured for the - * ADS7843 (it might have gotten configured for a different device while - * unlocked) - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_ADS7843E_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_ADS7843E_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Function: ads7843e_unlock - * - * Description: - * If we are sharing the SPI bus with other devices (CONFIG_SPI_OWNBUS - * undefined) then we need to un-lock the SPI bus for each transfer, - * possibly losing the current configuration. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void ads7843e_unlock(FAR struct spi_dev_s *spi) -{ - /* Relinquish the SPI bus. */ - - (void)SPI_LOCK(spi, false); -} -#endif - -/**************************************************************************** - * Function: ads7843e_configspi - * - * Description: - * Configure the SPI for use with the ADS7843E. This function should be - * called once during touchscreen initialization to configure the SPI - * bus. Note that if CONFIG_SPI_OWNBUS is not defined, then this function - * does nothing. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ads7843e_configspi(FAR struct spi_dev_s *spi) -{ - /* Configure SPI for the ADS7843. But only if we own the SPI bus. Otherwise, don't - * bother because it might change. - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_ADS7843E_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_ADS7843E_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Name: ads7843e_waitbusy - ****************************************************************************/ - -static inline void ads7843e_waitbusy(FAR struct ads7843e_dev_s *priv) -{ - while (priv->config->busy(priv->config)); -} - -/**************************************************************************** - * Name: ads7843e_sendcmd - ****************************************************************************/ - -static uint16_t ads7843e_sendcmd(FAR struct ads7843e_dev_s *priv, uint8_t cmd) -{ - uint8_t buffer[2]; - uint16_t result; - - /* Select the ADS7843E */ - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - - /* Send the command */ - - (void)SPI_SEND(priv->spi, cmd); - ads7843e_waitbusy(priv); - - /* Read the data */ - - SPI_RECVBLOCK(priv->spi, buffer, 2); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1]; - result = result >> 4; - - ivdbg("cmd:%02x response:%04x\n", cmd, result); - return result; -} - -/**************************************************************************** - * Name: ads7843e_notify - ****************************************************************************/ - -static void ads7843e_notify(FAR struct ads7843e_dev_s *priv) -{ -#ifndef CONFIG_DISABLE_POLL - int i; -#endif - - /* If there are threads waiting for read data, then signal one of them - * that the read data is available. - */ - - if (priv->nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the ADS7843E - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for ADS7843E data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_ADS7843E_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: ads7843e_sample - ****************************************************************************/ - -static int ads7843e_sample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample) -{ - irqstate_t flags; - int ret = -EAGAIN; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - */ - - flags = irqsave(); - - /* Is there new ADS7843E sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct ads7843e_sample_s )); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* Next.. no contact. Increment the ID so that next contact ID - * will be unique. X/Y positions are no longer valid. - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* First report -- next report will be a movement */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - irqrestore(flags); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_waitsample - ****************************************************************************/ - -static int ads7843e_waitsample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample) -{ - irqstate_t flags; - int ret; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - * - * In addition, we will also disable pre-emption to prevent other threads - * from getting control while we muck with the semaphores. - */ - - sched_lock(); - flags = irqsave(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->devsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is available. - */ - - while (ads7843e_sample(priv, sample) < 0) - { - /* Wait for a change in the ADS7843E state */ - - ivdbg("Waiting..\n"); - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - if (ret < 0) - { - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - ret = -EINTR; - goto errout; - } - } - - ivdbg("Sampled\n"); - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->devsem); - -errout: - /* Then re-enable interrupts. We might get interrupt here and there - * could be a new sample. But no new threads will run because we still - * have pre-emption disabled. - */ - - irqrestore(flags); - - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the ADS7843E for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_schedule - ****************************************************************************/ - -static int ads7843e_schedule(FAR struct ads7843e_dev_s *priv) -{ - FAR struct ads7843e_config_s *config; - int ret; - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts. ADS7843E interrupts will be re-enabled - * after the worker thread executes. - */ - - config->enable(config, false); - - /* Disable the watchdog timer. It will be re-enabled in the worker thread - * while the pen remains down. - */ - - wd_cancel(priv->wdog); - - /* Transfer processing to the worker thread. Since ADS7843E interrupts are - * disabled while the work is pending, no special action should be required - * to protected the work queue. - */ - - DEBUGASSERT(priv->work.worker == NULL); - ret = work_queue(HPWORK, &priv->work, ads7843e_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - - return OK; -} - -/**************************************************************************** - * Name: ads7843e_wdog - ****************************************************************************/ - -static void ads7843e_wdog(int argc, uint32_t arg1, ...) -{ - FAR struct ads7843e_dev_s *priv = (FAR struct ads7843e_dev_s *)((uintptr_t)arg1); - (void)ads7843e_schedule(priv); -} - -/**************************************************************************** - * Name: ads7843e_worker - ****************************************************************************/ - -static void ads7843e_worker(FAR void *arg) -{ - FAR struct ads7843e_dev_s *priv = (FAR struct ads7843e_dev_s *)arg; - FAR struct ads7843e_config_s *config; - uint16_t x; - uint16_t y; - uint16_t xdiff; - uint16_t ydiff; - bool pendown; - int ret; - - ASSERT(priv != NULL); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable the watchdog timer. This is safe because it is started only - * by this function and this function is serialized on the worker thread. - */ - - wd_cancel(priv->wdog); - - /* Lock the SPI bus so that we have exclusive access */ - - ads7843e_lock(priv->spi); - - /* Get exclusive access to the driver data structure */ - - do - { - ret = sem_wait(&priv->devsem); - - /* This should only fail if the wait was canceled by an signal - * (and the worker thread will receive a lot of signals). - */ - - DEBUGASSERT(ret == OK || errno == EINTR); - } - while (ret < 0); - - /* Check for pen up or down by reading the PENIRQ GPIO. */ - - pendown = config->pendown(config); - - /* Handle the change from pen down to pen up */ - - if (!pendown) - { - /* The pen is up.. reset thresholding variables. */ - - priv->threshx = INVALID_THRESHOLD; - priv->threshy = INVALID_THRESHOLD; - - /* Ignore the interrupt if the pen was already up (CONTACT_NONE == pen up - * and already reported; CONTACT_UP == pen up, but not reported) - */ - - if (priv->sample.contact == CONTACT_NONE || - priv->sample.contact == CONTACT_UP) - - { - goto ignored; - } - - /* The pen is up. NOTE: We know from a previous test, that this is a - * loss of contact condition. This will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* It is a pen down event. If the last loss-of-contact event has not been - * processed yet, then we have to ignore the pen down event (or else it will - * look like a drag event) - */ - - else if (priv->sample.contact == CONTACT_UP) - { - /* If we have not yet processed the last pen up event, then we - * cannot handle this pen down event. We will have to discard it. That - * should be okay because we will set the timer to to sample again - * later. - */ - - wd_start(priv->wdog, ADS7843E_WDOG_DELAY, ads7843e_wdog, 1, (uint32_t)priv); - goto ignored; - } - else - { - /* Handle pen down events. First, sample positional values. */ - -#ifdef CONFIG_ADS7843E_SWAPXY - x = ads7843e_sendcmd(priv, ADS7843_CMD_YPOSITION); - y = ads7843e_sendcmd(priv, ADS7843_CMD_XPOSITION); -#else - x = ads7843e_sendcmd(priv, ADS7843_CMD_XPOSITION); - y = ads7843e_sendcmd(priv, ADS7843_CMD_YPOSITION); -#endif - - /* Perform a thresholding operation so that the results will be more stable. - * If the difference from the last sample is small, then ignore the event. - * REVISIT: Should a large change in pressure also generate a event? - */ - - xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x); - ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y); - - /* Continue to sample the position while the pen is down */ - - wd_start(priv->wdog, ADS7843E_WDOG_DELAY, ads7843e_wdog, 1, (uint32_t)priv); - - /* Check the thresholds. Bail if there is no significant difference */ - - if (xdiff < CONFIG_ADS7843E_THRESHX && ydiff < CONFIG_ADS7843E_THRESHY) - { - /* Little or no change in either direction ... don't report anything. */ - - goto ignored; - } - - /* When we see a big difference, snap to the new x/y thresholds */ - - priv->threshx = x; - priv->threshy = y; - - /* Update the x/y position in the sample data */ - - priv->sample.x = priv->threshx; - priv->sample.y = priv->threshy; - - /* The X/Y positional data is now valid */ - - priv->sample.valid = true; - - /* If this is the first (acknowledged) pen down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - - /* Indicate the availability of new sample data for this ID */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that new ADS7843E data is available */ - - ads7843e_notify(priv); - - /* Exit, re-enabling ADS7843E interrupts */ - -ignored: - - (void)ads7843e_sendcmd(priv, ADS7843_CMD_ENABPINIRQ); - config->enable(config, true); - - /* Release our lock on the state structure and unlock the SPI bus */ - - sem_post(&priv->devsem); - ads7843e_unlock(priv->spi); -} - -/**************************************************************************** - * Name: ads7843e_interrupt - ****************************************************************************/ - -static int ads7843e_interrupt(int irq, FAR void *context) -{ - FAR struct ads7843e_dev_s *priv; - FAR struct ads7843e_config_s *config; - int ret; - - /* Which ADS7843E device caused the interrupt? */ - -#ifndef CONFIG_ADS7843E_MULTIPLE - priv = &g_ads7843e; -#else - for (priv = g_ads7843elist; - priv && priv->configs->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Schedule sampling to occur on the worker thread */ - - ret = ads7843e_schedule(priv); - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_open - ****************************************************************************/ - -static int ads7843e_open(FAR struct file *filep) -{ -#ifdef CONFIG_ADS7843E_REFCNT - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - uint8_t tmp; - int ret; - - ivdbg("Opening\n"); - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->devsem); - return ret; -#else - ivdbg("Opening\n"); - return OK; -#endif -} - -/**************************************************************************** - * Name: ads7843e_close - ****************************************************************************/ - -static int ads7843e_close(FAR struct file *filep) -{ -#ifdef CONFIG_ADS7843E_REFCNT - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - int ret; - - ivdbg("Closing\n"); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->devsem); -#endif - ivdbg("Closing\n"); - return OK; -} - -/**************************************************************************** - * Name: ads7843e_read - ****************************************************************************/ - -static ssize_t ads7843e_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - FAR struct touch_sample_s *report; - struct ads7843e_sample_s sample; - int ret; - - ivdbg("buffer:%p len:%d\n", buffer, len); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - idbg("Unsupported read size: %d\n", len); - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = ads7843e_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - ivdbg("Sample data is not available\n"); - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = ads7843e_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - idbg("ads7843e_waitsample: %d\n", ret); - goto errout; - } - } - - /* In any event, we now have sampled ADS7843E data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = sample.id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - - ivdbg(" id: %d\n", report->point[0].id); - ivdbg(" flags: %02x\n", report->point[0].flags); - ivdbg(" x: %d\n", report->point[0].x); - ivdbg(" y: %d\n", report->point[0].y); - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->devsem); - ivdbg("Returning: %d\n", ret); - return ret; -} - -/**************************************************************************** - * Name:ads7843e_ioctl - ****************************************************************************/ - -static int ads7843e_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = SPI_SETFREQUENCY(priv->spi, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int ads7843e_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - pollevent_t eventset; - int ndx; - int ret = OK; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_ADS7843E_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_ADS7843E_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - ads7843e_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->devsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ads7843e_register - * - * Description: - * Configure the ADS7843E to use the provided SPI device instance. This - * will register the driver as /dev/inputN where N is the minor device - * number - * - * Input Parameters: - * dev - An SPI driver instance - * config - Persistent board configuration data - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int ads7843e_register(FAR struct spi_dev_s *spi, - FAR struct ads7843e_config_s *config, int minor) -{ - FAR struct ads7843e_dev_s *priv; - char devname[DEV_NAMELEN]; -#ifdef CONFIG_ADS7843E_MULTIPLE - irqstate_t flags; -#endif - int ret; - - ivdbg("spi: %p minor: %d\n", spi, minor); - - /* Debug-only sanity checks */ - - DEBUGASSERT(spi != NULL && config != NULL && minor >= 0 && minor < 100); - - /* Create and initialize a ADS7843E device driver instance */ - -#ifndef CONFIG_ADS7843E_MULTIPLE - priv = &g_ads7843e; -#else - priv = (FAR struct ads7843e_dev_s *)kmalloc(sizeof(struct ads7843e_dev_s)); - if (!priv) - { - idbg("kmalloc(%d) failed\n", sizeof(struct ads7843e_dev_s)); - return -ENOMEM; - } -#endif - - /* Initialize the ADS7843E device driver instance */ - - memset(priv, 0, sizeof(struct ads7843e_dev_s)); - priv->spi = spi; /* Save the SPI device handle */ - priv->config = config; /* Save the board configuration */ - priv->wdog = wd_create(); /* Create a watchdog timer */ - priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */ - priv->threshy = INVALID_THRESHOLD; /* Initialize thresholding logic */ - - sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ - sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ - - /* Make sure that interrupts are disabled */ - - config->clear(config); - config->enable(config, false); - - /* Attach the interrupt handler */ - - ret = config->attach(config, ads7843e_interrupt); - if (ret < 0) - { - idbg("Failed to attach interrupt\n"); - goto errout_with_priv; - } - - idbg("Mode: %d Bits: 8 Frequency: %d\n", - CONFIG_ADS7843E_SPIMODE, CONFIG_ADS7843E_FREQUENCY); - - /* Lock the SPI bus so that we have exclusive access */ - - ads7843e_lock(spi); - - /* Configure the SPI interface */ - - ads7843e_configspi(spi); - - /* Enable the PEN IRQ */ - - ads7843e_sendcmd(priv, ADS7843_CMD_ENABPINIRQ); - - /* Unlock the bus */ - - ads7843e_unlock(spi); - - /* Register the device as an input device */ - - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ivdbg("Registering %s\n", devname); - - ret = register_driver(devname, &ads7843e_fops, 0666, priv); - if (ret < 0) - { - idbg("register_driver() failed: %d\n", ret); - goto errout_with_priv; - } - - /* If multiple ADS7843E devices are supported, then we will need to add - * this new instance to a list of device instances so that it can be - * found by the interrupt handler based on the recieved IRQ number. - */ - -#ifdef CONFIG_ADS7843E_MULTIPLE - priv->flink = g_ads7843elist; - g_ads7843elist = priv; - irqrestore(flags); -#endif - - /* Schedule work to perform the initial sampling and to set the data - * availability conditions. - */ - - ret = work_queue(HPWORK, &priv->work, ads7843e_worker, priv, 0); - if (ret != 0) - { - idbg("Failed to queue work: %d\n", ret); - goto errout_with_priv; - } - - /* And return success (?) */ - - return OK; - -errout_with_priv: - sem_destroy(&priv->devsem); -#ifdef CONFIG_ADS7843E_MULTIPLE - kfree(priv); -#endif - return ret; -} diff --git a/nuttx/drivers/input/ads7843e.h b/nuttx/drivers/input/ads7843e.h deleted file mode 100644 index 6fd70d98b..000000000 --- a/nuttx/drivers/input/ads7843e.h +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************************** - * drivers/input/ads7843e.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "Touch Screen Controller, ADS7843," Burr-Brown Products from Texas - * Instruments, SBAS090B, September 2000, Revised May 2002" - * - * See also: - * "Low Voltage I/O Touch Screen Controller, TSC2046," Burr-Brown Products - * from Texas Instruments, SBAS265F, October 2002, Revised August 2007." - * - * "XPT2046 Data Sheet," Shenzhen XPTek Technology Co., Ltd, 2007 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ********************************************************************************************/ - -#ifndef __DRIVERS_INPUT_ADS7843E_H -#define __DRIVERS_INPUT_ADS7843E_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ -/* Configuration ****************************************************************************/ -/* Reference counting is partially implemented, but not needed in the current design. */ - -#undef CONFIG_ADS7843E_REFCNT - -/* ADS7843E Interfaces *********************************************************************/ -/* ADS7843E command bit settings */ - -#define ADS7843E_CMD_PD0 (1 << 0) /* PD0 */ -#define ADS7843E_CMD_PD1 (1 << 1) /* PD1 */ -#define ADS7843E_CMD_DFR (1 << 2) /* SER/DFR */ -#define ADS7843E_CMD_EIGHT_BITS_MOD (1 << 3) /* Mode */ -#define ADS7843E_CMD_START (1 << 7) /* Start Bit */ -#define ADS7843E_CMD_SWITCH_SHIFT 4 /* Address setting */ - -/* ADS7843E Commands */ - -#define ADS7843_CMD_YPOSITION \ - ((1 << ADS7843E_CMD_SWITCH_SHIFT)|ADS7843E_CMD_START|ADS7843E_CMD_PD0|ADS7843E_CMD_PD1) -#define ADS7843_CMD_XPOSITION \ - ((5 << ADS7843E_CMD_SWITCH_SHIFT)|ADS7843E_CMD_START|ADS7843E_CMD_PD0|ADS7843E_CMD_PD1) -#define ADS7843_CMD_ENABPINIRQ \ - ((1 << ADS7843E_CMD_SWITCH_SHIFT)|ADS7843E_CMD_START) - -/* Driver support **************************************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* Poll the pen position while the pen is down at this rate (50MS): */ - -#define ADS7843E_WDOG_DELAY ((50 + (MSEC_PER_TICK-1))/ MSEC_PER_TICK) - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ - -/* This describes the state of one contact */ - -enum ads7843e_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one ADS7843E sample */ - -struct ads7843e_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum ads7843e_contact_e) */ - bool valid; /* True: x,y contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ -}; - -/* This structure describes the state of one ADS7843E driver instance */ - -struct ads7843e_dev_s -{ -#ifdef CONFIG_ADS7843E_MULTIPLE - FAR struct ads7843e_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif -#ifdef CONFIG_ADS7843E_REFCNT - uint8_t crefs; /* Number of times the device has been opened */ -#endif - uint8_t nwaiters; /* Number of threads waiting for ADS7843E data */ - uint8_t id; /* Current touch point ID */ - volatile bool penchange; /* An unreported event is buffered */ - uint16_t threshx; /* Thresholding X value */ - uint16_t threshy; /* Thresholding Y value */ - sem_t devsem; /* Manages exclusive access to this structure */ - sem_t waitsem; /* Used to wait for the availability of data */ - - FAR struct ads7843e_config_s *config; /* Board configuration data */ - FAR struct spi_dev_s *spi; /* Saved SPI driver instance */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - struct ads7843e_sample_s sample; /* Last sampled touch point data */ - WDOG_ID wdog; /* Poll the position while the pen is down */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_ADS7843E_NPOLLWAITERS]; -#endif -}; - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_INPUT_ADS7843E_H */ diff --git a/nuttx/drivers/input/max11802.c b/nuttx/drivers/input/max11802.c deleted file mode 100644 index ea3883cd0..000000000 --- a/nuttx/drivers/input/max11802.c +++ /dev/null @@ -1,1313 +0,0 @@ -/**************************************************************************** - * drivers/input/max11802.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * Petteri Aimonen - * - * References: - * "Low-Power, Ultra-Small Resistive Touch-Screen Controllers - * with I2C/SPI Interface" Maxim IC, Rev 3, 10/2010 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "max11802.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* This is a value for the threshold that guantees a big difference on the - * first pendown (but can't overflow). - */ - -#define INVALID_THRESHOLD 0x1000 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void max11802_configspi(FAR struct spi_dev_s *spi); -# define max11802_lock(spi) -# define max11802_unlock(spi) -#else -# define max11802_configspi(spi); -static void max11802_lock(FAR struct spi_dev_s *spi); -static void max11802_unlock(FAR struct spi_dev_s *spi); -#endif - -static uint16_t max11802_sendcmd(FAR struct max11802_dev_s *priv, uint8_t cmd, int *tags); - -/* Interrupts and data sampling */ - -static void max11802_notify(FAR struct max11802_dev_s *priv); -static int max11802_sample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample); -static int max11802_waitsample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample); -static void max11802_worker(FAR void *arg); -static int max11802_interrupt(int irq, FAR void *context); - -/* Character driver methods */ - -static int max11802_open(FAR struct file *filep); -static int max11802_close(FAR struct file *filep); -static ssize_t max11802_read(FAR struct file *filep, FAR char *buffer, size_t len); -static int max11802_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int max11802_poll(FAR struct file *filep, struct pollfd *fds, bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This the the vtable that supports the character driver interface */ - -static const struct file_operations max11802_fops = -{ - max11802_open, /* open */ - max11802_close, /* close */ - max11802_read, /* read */ - 0, /* write */ - 0, /* seek */ - max11802_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , max11802_poll /* poll */ -#endif -}; - -/* If only a single MAX11802 device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_MAX11802_MULTIPLE -static struct max11802_dev_s g_max11802; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct max11802_dev_s *g_max11802list; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: max11802_lock - * - * Description: - * Lock the SPI bus and re-configure as necessary. This function must be - * to assure: (1) exclusive access to the SPI bus, and (2) to assure that - * the shared bus is properly configured for the touchscreen controller. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void max11802_lock(FAR struct spi_dev_s *spi) -{ - /* Lock the SPI bus because there are multiple devices competing for the - * SPI bus - */ - - (void)SPI_LOCK(spi, true); - - /* We have the lock. Now make sure that the SPI bus is configured for the - * MAX11802 (it might have gotten configured for a different device while - * unlocked) - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_MAX11802_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_MAX11802_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Function: max11802_unlock - * - * Description: - * If we are sharing the SPI bus with other devices (CONFIG_SPI_OWNBUS - * undefined) then we need to un-lock the SPI bus for each transfer, - * possibly losing the current configuration. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void max11802_unlock(FAR struct spi_dev_s *spi) -{ - /* Relinquish the SPI bus. */ - - (void)SPI_LOCK(spi, false); -} -#endif - -/**************************************************************************** - * Function: max11802_configspi - * - * Description: - * Configure the SPI for use with the MAX11802. This function should be - * called once during touchscreen initialization to configure the SPI - * bus. Note that if CONFIG_SPI_OWNBUS is not defined, then this function - * does nothing. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void max11802_configspi(FAR struct spi_dev_s *spi) -{ - /* Configure SPI for the MAX11802. But only if we own the SPI bus. Otherwise, don't - * bother because it might change. - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_MAX11802_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_MAX11802_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Name: max11802_sendcmd - ****************************************************************************/ - -static uint16_t max11802_sendcmd(FAR struct max11802_dev_s *priv, uint8_t cmd, int *tags) -{ - uint8_t buffer[2]; - uint16_t result; - - /* Select the MAX11802 */ - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - - /* Send the command */ - - (void)SPI_SEND(priv->spi, cmd); - - /* Read the data */ - - SPI_RECVBLOCK(priv->spi, buffer, 2); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1]; - *tags = result & 0xF; - result >>= 4; // Get rid of tags - - ivdbg("cmd:%02x response:%04x\n", cmd, result); - return result; -} - -/**************************************************************************** - * Name: max11802_notify - ****************************************************************************/ - -static void max11802_notify(FAR struct max11802_dev_s *priv) -{ -#ifndef CONFIG_DISABLE_POLL - int i; -#endif - - /* If there are threads waiting for read data, then signal one of them - * that the read data is available. - */ - - if (priv->nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the sample - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for MAX11802 data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: max11802_sample - ****************************************************************************/ - -static int max11802_sample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample) -{ - irqstate_t flags; - int ret = -EAGAIN; - - /* Interrupts must be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - */ - - flags = irqsave(); - - /* Is there new MAX11802 sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct max11802_sample_s )); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* Next.. no contact. Increment the ID so that next contact ID - * will be unique. X/Y positions are no longer valid. - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* First report -- next report will be a movement */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - irqrestore(flags); - return ret; -} - -/**************************************************************************** - * Name: max11802_waitsample - ****************************************************************************/ - -static int max11802_waitsample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample) -{ - irqstate_t flags; - int ret; - - /* Interrupts must be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - * - * In addition, we will also disable pre-emption to prevent other threads - * from getting control while we muck with the semaphores. - */ - - sched_lock(); - flags = irqsave(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->devsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is available. - */ - - while (max11802_sample(priv, sample) < 0) - { - /* Wait for a change in the MAX11802 state */ - - ivdbg("Waiting..\n"); - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - if (ret < 0) - { - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - ret = -EINTR; - goto errout; - } - } - - ivdbg("Sampled\n"); - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->devsem); - -errout: - /* Then re-enable interrupts. We might get interrupt here and there - * could be a new sample. But no new threads will run because we still - * have pre-emption disabled. - */ - - irqrestore(flags); - - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the MAX11802 for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: max11802_schedule - ****************************************************************************/ - -static int max11802_schedule(FAR struct max11802_dev_s *priv) -{ - FAR struct max11802_config_s *config; - int ret; - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts. MAX11802 interrupts will be re-enabled - * after the worker thread executes. - */ - - config->enable(config, false); - - /* Disable the watchdog timer. It will be re-enabled in the worker thread - * while the pen remains down. - */ - - wd_cancel(priv->wdog); - - /* Transfer processing to the worker thread. Since MAX11802 interrupts are - * disabled while the work is pending, no special action should be required - * to protected the work queue. - */ - - DEBUGASSERT(priv->work.worker == NULL); - ret = work_queue(HPWORK, &priv->work, max11802_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - - return OK; -} - -/**************************************************************************** - * Name: max11802_wdog - ****************************************************************************/ - -static void max11802_wdog(int argc, uint32_t arg1, ...) -{ - FAR struct max11802_dev_s *priv = (FAR struct max11802_dev_s *)((uintptr_t)arg1); - (void)max11802_schedule(priv); -} - -/**************************************************************************** - * Name: max11802_worker - ****************************************************************************/ - -static void max11802_worker(FAR void *arg) -{ - FAR struct max11802_dev_s *priv = (FAR struct max11802_dev_s *)arg; - FAR struct max11802_config_s *config; - uint16_t x; - uint16_t y; - uint16_t xdiff; - uint16_t ydiff; - bool pendown; - int ret; - int tags, tags2; - - ASSERT(priv != NULL); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable the watchdog timer. This is safe because it is started only - * by this function and this function is serialized on the worker thread. - */ - - wd_cancel(priv->wdog); - - /* Lock the SPI bus so that we have exclusive access */ - - max11802_lock(priv->spi); - - /* Start coordinate measurement */ - (void)max11802_sendcmd(priv, MAX11802_CMD_MEASUREXY, &tags); - - /* Get exclusive access to the driver data structure */ - - do - { - ret = sem_wait(&priv->devsem); - - /* This should only fail if the wait was canceled by an signal - * (and the worker thread will receive a lot of signals). - */ - - DEBUGASSERT(ret == OK || errno == EINTR); - } - while (ret < 0); - - /* Check for pen up or down by reading the PENIRQ GPIO. */ - - pendown = config->pendown(config); - - /* Handle the change from pen down to pen up */ - - if (pendown) - ivdbg("\nPD\n"); - else - ivdbg("\nPU\n"); - - if (!pendown) - { - /* The pen is up.. reset thresholding variables. */ - - priv->threshx = INVALID_THRESHOLD; - priv->threshy = INVALID_THRESHOLD; - - /* Ignore the interrupt if the pen was already up (CONTACT_NONE == pen up - * and already reported; CONTACT_UP == pen up, but not reported) - */ - - ivdbg("\nPC%d\n", priv->sample.contact); - - if (priv->sample.contact == CONTACT_NONE || - priv->sample.contact == CONTACT_UP) - - { - goto ignored; - } - - /* The pen is up. NOTE: We know from a previous test, that this is a - * loss of contact condition. This will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* It is a pen down event. If the last loss-of-contact event has not been - * processed yet, then we have to ignore the pen down event (or else it will - * look like a drag event) - */ - - else if (priv->sample.contact == CONTACT_UP) - { - /* If we have not yet processed the last pen up event, then we - * cannot handle this pen down event. We will have to discard it. That - * should be okay because we will set the timer to to sample again - * later. - */ - - ivdbg("Previous pen up event still in buffer\n"); - max11802_notify(priv); - wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1, (uint32_t)priv); - goto ignored; - } - else - { - /* Wait for data ready */ - do { - /* Handle pen down events. First, sample positional values. */ - -#ifdef CONFIG_MAX11802_SWAPXY - x = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags); - y = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags2); -#else - x = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags); - y = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags2); -#endif - } while (tags == 0xF || tags2 == 0xF); - - /* Continue to sample the position while the pen is down */ - wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1, (uint32_t)priv); - - /* Check if data is valid */ - if ((tags & 0x03) != 0) - { - ivdbg("Touch ended before measurement\n"); - goto ignored; - } - - /* Perform a thresholding operation so that the results will be more stable. - * If the difference from the last sample is small, then ignore the event. - * REVISIT: Should a large change in pressure also generate a event? - */ - - xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x); - ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y); - - /* Check the thresholds. Bail if there is no significant difference */ - - if (xdiff < CONFIG_MAX11802_THRESHX && ydiff < CONFIG_MAX11802_THRESHY) - { - /* Little or no change in either direction ... don't report anything. */ - - goto ignored; - } - - /* When we see a big difference, snap to the new x/y thresholds */ - - priv->threshx = x; - priv->threshy = y; - - /* Update the x/y position in the sample data */ - - priv->sample.x = priv->threshx; - priv->sample.y = priv->threshy; - - /* The X/Y positional data is now valid */ - - priv->sample.valid = true; - - /* If this is the first (acknowledged) pen down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - - /* Indicate the availability of new sample data for this ID */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that new MAX11802 data is available */ - - max11802_notify(priv); - -ignored: - config->enable(config, true); - - /* Release our lock on the state structure and unlock the SPI bus */ - - sem_post(&priv->devsem); - max11802_unlock(priv->spi); -} - -/**************************************************************************** - * Name: max11802_interrupt - ****************************************************************************/ - -static int max11802_interrupt(int irq, FAR void *context) -{ - FAR struct max11802_dev_s *priv; - FAR struct max11802_config_s *config; - int ret; - - /* Which MAX11802 device caused the interrupt? */ - -#ifndef CONFIG_MAX11802_MULTIPLE - priv = &g_max11802; -#else - for (priv = g_max11802list; - priv && priv->configs->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Schedule sampling to occur on the worker thread */ - - ret = max11802_schedule(priv); - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return ret; -} - -/**************************************************************************** - * Name: max11802_open - ****************************************************************************/ - -static int max11802_open(FAR struct file *filep) -{ -#ifdef CONFIG_MAX11802_REFCNT - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - uint8_t tmp; - int ret; - - ivdbg("Opening\n"); - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->devsem); - return ret; -#else - ivdbg("Opening\n"); - return OK; -#endif -} - -/**************************************************************************** - * Name: max11802_close - ****************************************************************************/ - -static int max11802_close(FAR struct file *filep) -{ -#ifdef CONFIG_MAX11802_REFCNT - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - int ret; - - ivdbg("Closing\n"); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->devsem); -#endif - ivdbg("Closing\n"); - return OK; -} - -/**************************************************************************** - * Name: max11802_read - ****************************************************************************/ - -static ssize_t max11802_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - FAR struct touch_sample_s *report; - struct max11802_sample_s sample; - int ret; - - ivdbg("buffer:%p len:%d\n", buffer, len); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - idbg("Unsupported read size: %d\n", len); - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = max11802_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - ivdbg("Sample data is not available\n"); - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = max11802_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - idbg("max11802_waitsample: %d\n", ret); - goto errout; - } - } - - /* In any event, we now have sampled MAX11802 data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = sample.id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - - ivdbg(" id: %d\n", report->point[0].id); - ivdbg(" flags: %02x\n", report->point[0].flags); - ivdbg(" x: %d\n", report->point[0].x); - ivdbg(" y: %d\n", report->point[0].y); - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->devsem); - ivdbg("Returning: %d\n", ret); - return ret; -} - -/**************************************************************************** - * Name:max11802_ioctl - ****************************************************************************/ - -static int max11802_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = SPI_SETFREQUENCY(priv->spi, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name: max11802_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int max11802_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - pollevent_t eventset; - int ndx; - int ret = OK; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_MAX11802_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - max11802_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->devsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: max11802_register - * - * Description: - * Configure the MAX11802 to use the provided SPI device instance. This - * will register the driver as /dev/inputN where N is the minor device - * number - * - * Input Parameters: - * dev - An SPI driver instance - * config - Persistent board configuration data - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int max11802_register(FAR struct spi_dev_s *spi, - FAR struct max11802_config_s *config, int minor) -{ - FAR struct max11802_dev_s *priv; - char devname[DEV_NAMELEN]; -#ifdef CONFIG_MAX11802_MULTIPLE - irqstate_t flags; -#endif - int ret; - - ivdbg("spi: %p minor: %d\n", spi, minor); - - /* Debug-only sanity checks */ - - DEBUGASSERT(spi != NULL && config != NULL && minor >= 0 && minor < 100); - - /* Create and initialize a MAX11802 device driver instance */ - -#ifndef CONFIG_MAX11802_MULTIPLE - priv = &g_max11802; -#else - priv = (FAR struct max11802_dev_s *)kmalloc(sizeof(struct max11802_dev_s)); - if (!priv) - { - idbg("kmalloc(%d) failed\n", sizeof(struct max11802_dev_s)); - return -ENOMEM; - } -#endif - - /* Initialize the MAX11802 device driver instance */ - - memset(priv, 0, sizeof(struct max11802_dev_s)); - priv->spi = spi; /* Save the SPI device handle */ - priv->config = config; /* Save the board configuration */ - priv->wdog = wd_create(); /* Create a watchdog timer */ - priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */ - priv->threshy = INVALID_THRESHOLD; /* Initialize thresholding logic */ - - sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ - sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ - - /* Make sure that interrupts are disabled */ - - config->clear(config); - config->enable(config, false); - - /* Attach the interrupt handler */ - - ret = config->attach(config, max11802_interrupt); - if (ret < 0) - { - idbg("Failed to attach interrupt\n"); - goto errout_with_priv; - } - - idbg("Mode: %d Bits: 8 Frequency: %d\n", - CONFIG_MAX11802_SPIMODE, CONFIG_MAX11802_FREQUENCY); - - /* Lock the SPI bus so that we have exclusive access */ - - max11802_lock(spi); - - /* Configure the SPI interface */ - - max11802_configspi(spi); - - /* Configure MAX11802 registers */ - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_WR); - (void)SPI_SEND(priv->spi, MAX11802_MODE); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_AVG_WR); - (void)SPI_SEND(priv->spi, MAX11802_AVG); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_TIMING_WR); - (void)SPI_SEND(priv->spi, MAX11802_TIMING); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_DELAY_WR); - (void)SPI_SEND(priv->spi, MAX11802_DELAY); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - /* Test that the device access was successful. */ - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_RD); - ret = SPI_SEND(priv->spi, 0); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - /* Unlock the bus */ - max11802_unlock(spi); - - if (ret != MAX11802_MODE) - { - idbg("max11802 mode readback failed: %02x\n", ret); - goto errout_with_priv; - } - - /* Register the device as an input device */ - - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ivdbg("Registering %s\n", devname); - - ret = register_driver(devname, &max11802_fops, 0666, priv); - if (ret < 0) - { - idbg("register_driver() failed: %d\n", ret); - goto errout_with_priv; - } - - /* If multiple MAX11802 devices are supported, then we will need to add - * this new instance to a list of device instances so that it can be - * found by the interrupt handler based on the recieved IRQ number. - */ - -#ifdef CONFIG_MAX11802_MULTIPLE - priv->flink = g_max11802list; - g_max11802list = priv; - irqrestore(flags); -#endif - - /* Schedule work to perform the initial sampling and to set the data - * availability conditions. - */ - - ret = work_queue(HPWORK, &priv->work, max11802_worker, priv, 0); - if (ret != 0) - { - idbg("Failed to queue work: %d\n", ret); - goto errout_with_priv; - } - - /* And return success (?) */ - - return OK; - -errout_with_priv: - sem_destroy(&priv->devsem); -#ifdef CONFIG_MAX11802_MULTIPLE - kfree(priv); -#endif - return ret; -} diff --git a/nuttx/drivers/input/max11802.h b/nuttx/drivers/input/max11802.h deleted file mode 100644 index b6beec045..000000000 --- a/nuttx/drivers/input/max11802.h +++ /dev/null @@ -1,167 +0,0 @@ -/******************************************************************************************** - * drivers/input/max11802.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * Petteri Aimonen - * - * References: - * "Low-Power, Ultra-Small Resistive Touch-Screen Controllers - * with I2C/SPI Interface" Maxim IC, Rev 3, 10/2010 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ********************************************************************************************/ - -#ifndef __DRIVERS_INPUT_MAX11802_H -#define __DRIVERS_INPUT_MAX11802_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ -/* Configuration ****************************************************************************/ - -/* MAX11802 Interfaces *********************************************************************/ - -/* LSB of register addresses specifies read (1) or write (0). */ -#define MAX11802_CMD_XPOSITION ((0x52 << 1) | 1) -#define MAX11802_CMD_YPOSITION ((0x54 << 1) | 1) -#define MAX11802_CMD_MEASUREXY (0x70 << 1) -#define MAX11802_CMD_MODE_WR (0x0B << 1) -#define MAX11802_CMD_MODE_RD ((0x0B << 1) | 1) -#define MAX11802_CMD_AVG_WR (0x03 << 1) -#define MAX11802_CMD_TIMING_WR (0x05 << 1) -#define MAX11802_CMD_DELAY_WR (0x06 << 1) - -/* Register values to set */ -#define MAX11802_MODE 0x0E -#define MAX11802_AVG 0x55 -#define MAX11802_TIMING 0x77 -#define MAX11802_DELAY 0x55 - -/* Driver support **************************************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* Poll the pen position while the pen is down at this rate (50MS): */ - -#define MAX11802_WDOG_DELAY ((50 + (MSEC_PER_TICK-1))/ MSEC_PER_TICK) - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ - -/* This describes the state of one contact */ - -enum max11802_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one MAX11802 sample */ - -struct max11802_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum ads7843e_contact_e) */ - bool valid; /* True: x,y contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ -}; - -/* This structure describes the state of one MAX11802 driver instance */ - -struct max11802_dev_s -{ -#ifdef CONFIG_ADS7843E_MULTIPLE - FAR struct ads7843e_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif - uint8_t nwaiters; /* Number of threads waiting for MAX11802 data */ - uint8_t id; /* Current touch point ID */ - volatile bool penchange; /* An unreported event is buffered */ - uint16_t threshx; /* Thresholding X value */ - uint16_t threshy; /* Thresholding Y value */ - sem_t devsem; /* Manages exclusive access to this structure */ - sem_t waitsem; /* Used to wait for the availability of data */ - - FAR struct max11802_config_s *config; /* Board configuration data */ - FAR struct spi_dev_s *spi; /* Saved SPI driver instance */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - struct max11802_sample_s sample; /* Last sampled touch point data */ - WDOG_ID wdog; /* Poll the position while the pen is down */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_ADS7843E_NPOLLWAITERS]; -#endif -}; - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_INPUT_ADS7843E_H */ diff --git a/nuttx/drivers/input/stmpe811.h b/nuttx/drivers/input/stmpe811.h deleted file mode 100644 index f6d646527..000000000 --- a/nuttx/drivers/input/stmpe811.h +++ /dev/null @@ -1,245 +0,0 @@ -/******************************************************************************************** - * drivers/input/stmpe811.h - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ********************************************************************************************/ - -#ifndef __DRIVERS_INPUT_STMPE811_H -#define __DRIVERS_INPUT_STMPE811_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -#include - -#include -#include - -#include -#include -#include - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ -/* Configuration ****************************************************************************/ -/* Reference counting is partially implemented, but not needed in the current design. - */ - -#undef CONFIG_STMPE811_REFCNT - -/* No support for the SPI interface yet */ - -#ifdef CONFIG_STMPE811_SPI -# error "Only the STMPE811 I2C interface is supported by this driver" -#endif - -/* Driver support ***************************************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It defined here - * so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* STMPE811 Resources ************************************************************************/ -#ifndef CONFIG_STMPE811_TSC_DISABLE -# define STMPE811_ADC_NPINS 4 /* Only pins 0-3 can be used for ADC */ -# define STMPE811_GPIO_NPINS 4 /* Only pins 0-3 can be used as GPIOs */ -#else -# define STMPE811_ADC_NPINS 8 /* All pins can be used for ADC */ -# define STMPE811_GPIO_NPINS 8 /* All pins can be used as GPIOs */ -#endif - -/* Driver flags */ - -#define STMPE811_FLAGS_TSC_INITIALIZED (1 << 0) /* 1: The TSC block has been initialized */ -#define STMPE811_FLAGS_GPIO_INITIALIZED (1 << 1) /* 1: The GIO block has been initialized */ -#define STMPE811_FLAGS_ADC_INITIALIZED (1 << 2) /* 1: The ADC block has been initialized */ -#define STMPE811_FLAGS_TS_INITIALIZED (1 << 3) /* 1: The TS block has been initialized */ - -/* Timeout to detect missing pen up events */ - -#define STMPE811_PENUP_TICKS ((100 + (MSEC_PER_TICK-1)) / MSEC_PER_TICK) - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ -/* This describes the state of one contact */ - -enum stmpe811_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one STMPE811 sample */ - -struct stmpe811_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum stmpe811_contact_e) */ - bool valid; /* True: x,y,z contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ - uint8_t z; /* Measured Z index */ -}; - -/* This structure represents the state of the STMPE811 driver */ - -struct stmpe811_dev_s -{ -#ifdef CONFIG_STMPE811_MULTIPLE - FAR struct stmpe811_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif - - /* Common fields */ - - FAR struct stmpe811_config_s *config; /* Board configuration data */ - sem_t exclsem; /* Manages exclusive access to this structure */ -#ifdef CONFIG_STMPE811_SPI - FAR struct spi_dev_s *spi; /* Saved SPI driver instance */ -#else - FAR struct i2c_dev_s *i2c; /* Saved I2C driver instance */ -#endif - - uint8_t inuse; /* STMPE811 pins in use */ - uint8_t flags; /* See STMPE811_FLAGS_* definitions */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - - /* Fields that may be disabled to save size if touchscreen support is not used. */ - -#ifndef CONFIG_STMPE811_TSC_DISABLE -#ifdef CONFIG_STMPE811_REFCNT - uint8_t crefs; /* Number of times the device has been opened */ -#endif - uint8_t nwaiters; /* Number of threads waiting for STMPE811 data */ - uint8_t id; /* Current touch point ID */ - uint8_t minor; /* Touchscreen minor device number */ - volatile bool penchange; /* An unreported event is buffered */ - - uint16_t threshx; /* Thresholded X value */ - uint16_t threshy; /* Thresholded Y value */ - sem_t waitsem; /* Used to wait for the availability of data */ - - struct work_s timeout; /* Supports tiemeout work */ - WDOG_ID wdog; /* Timeout to detect missing pen down events */ - struct stmpe811_sample_s sample; /* Last sampled touch point data */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_STMPE811_NPOLLWAITERS]; -#endif -#endif - - /* Fields that may be disabled to save size of GPIO support is not used */ - -#if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE) - stmpe811_handler_t handlers[STMPE811_GPIO_NPINS]; /* GPIO "interrupt handlers" */ -#endif -}; - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -/******************************************************************************************** - * Name: stmpe811_getreg8 - * - * Description: - * Read from an 8-bit STMPE811 register - * - ********************************************************************************************/ - -uint8_t stmpe811_getreg8(FAR struct stmpe811_dev_s *priv, uint8_t regaddr); - -/******************************************************************************************** - * Name: stmpe811_putreg8 - * - * Description: - * Write a value to an 8-bit STMPE811 register - * - ********************************************************************************************/ - -void stmpe811_putreg8(FAR struct stmpe811_dev_s *priv, uint8_t regaddr, uint8_t regval); - -/******************************************************************************************** - * Name: stmpe811_getreg16 - * - * Description: - * Read 16-bits of data from an STMPE-11 register - * - ********************************************************************************************/ - -uint16_t stmpe811_getreg16(FAR struct stmpe811_dev_s *priv, uint8_t regaddr); - -/******************************************************************************************** - * Name: stmpe811_tscint - * - * Description: - * Handle touchscreen interrupt events (this function actually executes in the context of - * the worker thread). - * - ********************************************************************************************/ - -#ifndef CONFIG_STMPE811_TSC_DISABLE -void stmpe811_tscworker(FAR struct stmpe811_dev_s *priv, uint8_t intsta) weak_function; -#endif - -/******************************************************************************************** - * Name: stmpe811_gpioworker - * - * Description: - * Handle GPIO interrupt events (this function actually executes in the context of the - * worker thread). - * - ********************************************************************************************/ - -#if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE) -void stmpe811_gpioworker(FAR struct stmpe811_dev_s *priv) weak_function; -#endif - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 */ -#endif /* __DRIVERS_INPUT_STMPE811_H */ diff --git a/nuttx/drivers/input/stmpe811_adc.c b/nuttx/drivers/input/stmpe811_adc.c deleted file mode 100644 index 1ffe987e6..000000000 --- a/nuttx/drivers/input/stmpe811_adc.c +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_adc.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include -#include - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_ADC_DISABLE) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_adcinitialize - * - * Description: - * Configure for ADC mode operation. Set overall ADC ADC timing that - * applies to all pins. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_adcinitialize(STMPE811_HANDLE handle) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t regval; - int ret; - - DEBUGASSERT(handle); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Enable Clocking for ADC */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~SYS_CTRL2_ADC_OFF; - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Select Sample Time, bit number and ADC Reference */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL1, priv->config->ctrl1); - - /* Wait for 20 ms */ - - up_mdelay(20); - - /* Select the ADC clock speed */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL2, priv->config->ctrl2); - - /* Mark ADC initialized */ - - priv->flags |= STMPE811_FLAGS_ADC_INITIALIZED; - sem_post(&priv->exclsem); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_adcconfig - * - * Description: - * Configure a pin for ADC input. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pin - The ADC pin number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_adcconfig(STMPE811_HANDLE handle, int pin) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t pinmask = GPIO_PIN(pin); - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_ADC_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the pin is not already in use */ - - if ((priv->inuse & pinmask) != 0) - { - idbg("PIN%d is already in-use\n", pin); - sem_post(&priv->exclsem); - return -EBUSY; - } - - /* Clear the alternate function bit for the pin, making it an ADC input - * (or perhaps an an external reference, depending on the state of the - * ADC_CTRL1_REF_SEL bit). - */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_AF); - regval &= ~pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval); - - /* Mark the pin as 'in use' */ - - priv->inuse |= pinmask; - sem_post(&priv->exclsem); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_adcread - * - * Description: - * Read the converted analog input value from the select pin. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pin - The ADC pin number - * - * Returned Value: - * The converted value (there is no error reporting mechanism). - * - ****************************************************************************/ - -uint16_t stmpe811_adcread(STMPE811_HANDLE handle, int pin) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t pinmask = GPIO_PIN(pin); - uint8_t regval; - int i; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < 8); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Request AD conversion by setting the bit corresponding the pin in the - * ADC CAPT register. - */ - - stmpe811_putreg8(priv, STMPE811_ADC_CAPT, pinmask); - - /* Wait for the conversion to complete. The ADC CAPT register reads '1' - * if conversion is completed. Reads '0' if conversion is in progress. - * Try three times before giving up. - */ - - for (i = 0; i < 3; i++) - { - /* The worst case ADC conversion time is (nominally) 56.4 uS. The - * following usleep() looks nice but in reality, the usleep() - * does not have that kind of precision (it will probably end up - * waiting 10 MS). - */ - - usleep(57); - - /* Check if the conversion is complete */ - - regval = stmpe811_getreg8(priv, STMPE811_ADC_CAPT); - if ((regval & pinmask) != 0) - { - break; - } - } - - /* At the completion of the conversion, return whatever we read from - * from the channel register associated with the pin. - */ - - return stmpe811_getreg16(priv, STMPE811_ADC_DATACH(pin)); -} - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_ADC_DISABLE */ - diff --git a/nuttx/drivers/input/stmpe811_base.c b/nuttx/drivers/input/stmpe811_base.c deleted file mode 100644 index f37c24622..000000000 --- a/nuttx/drivers/input/stmpe811_base.c +++ /dev/null @@ -1,546 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_base.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* If only a single STMPE811 device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_STMPE811_MULTIPLE -static struct stmpe811_dev_s g_stmpe811; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct stmpe811_dev_s *g_stmpe811list; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_worker - * - * Description: - * This is the "bottom half" of the STMPE811 interrupt handler - * - ****************************************************************************/ - -static void stmpe811_worker(FAR void *arg) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)arg; - uint8_t regval; - - DEBUGASSERT(priv && priv->config); - - /* Get the global interrupt status */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_STA); - - /* Check for a touchscreen interrupt */ - -#ifndef CONFIG_STMPE811_TSC_DISABLE - if ((regval & (INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW)) != 0) - { - /* Dispatch the touchscreen interrupt if it was brought into the link */ - -#ifdef CONFIG_HAVE_WEAKFUNCTIONS - if (stmpe811_tscworker) -#endif - { - stmpe811_tscworker(priv, regval); - } - - stmpe811_putreg8(priv, STMPE811_INT_STA, (INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW)); - regval &= ~(INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW); - } -#endif - -#if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE) - if ((regval & INT_GPIO) != 0) - { - /* Dispatch the GPIO interrupt if it was brought into the link */ - -#ifdef CONFIG_HAVE_WEAKFUNCTIONS - if (stmpe811_gpioworker) -#endif - { - stmpe811_gpioworker(priv); - } - - stmpe811_putreg8(priv, STMPE811_INT_STA, INT_GPIO); - regval &= ~INT_GPIO; - } -#endif - - /* Clear any other residual, unhandled pending interrupt */ - - if (regval != 0) - { - stmpe811_putreg8(priv, STMPE811_INT_STA, regval); - } - - /* Re-enable the STMPE811 GPIO interrupt */ - - priv->config->enable(priv->config, true); -} - -/**************************************************************************** - * Name: stmpe811_interrupt - * - * Description: - * The STMPE811 interrupt handler - * - ****************************************************************************/ - -static int stmpe811_interrupt(int irq, FAR void *context) -{ - FAR struct stmpe811_dev_s *priv; - FAR struct stmpe811_config_s *config; - int ret; - - /* Which STMPE811 device caused the interrupt? */ - -#ifndef CONFIG_STMPE811_MULTIPLE - priv = &g_stmpe811; -#else - for (priv = g_stmpe811list; - priv && priv->config->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts */ - - config->enable(config, false); - - /* Check if interrupt work is already queue. If it is already busy, then - * we already have interrupt processing in the pipeline and we need to do - * nothing more. - */ - - if (work_available(&priv->work)) - { - /* Yes.. Transfer processing to the worker thread. Since STMPE811 - * interrupts are disabled while the work is pending, no special - * action should be required to protect the work queue. - */ - - ret = work_queue(HPWORK, &priv->work, stmpe811_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - } - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_checkid - * - * Description: - * Read and verify the STMPE811 chip ID - * - ****************************************************************************/ - -static int stmpe811_checkid(FAR struct stmpe811_dev_s *priv) -{ - uint16_t devid = 0; - - /* Read device ID */ - - devid = stmpe811_getreg8(priv, STMPE811_CHIP_ID); - devid = (uint32_t)(devid << 8); - devid |= (uint32_t)stmpe811_getreg8(priv, STMPE811_CHIP_ID+1); - ivdbg("devid: %04x\n", devid); - - if (devid != (uint16_t)CHIP_ID) - { - /* ID is not Correct */ - - return -ENODEV; - } - - return OK; -} - -/**************************************************************************** - * Name: stmpe811_reset - * - * Description: - * Reset the STMPE811 - * - ****************************************************************************/ - -static void stmpe811_reset(FAR struct stmpe811_dev_s *priv) -{ - /* Power Down the STMPE811 */ - - stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, SYS_CTRL1_SOFTRESET); - - /* Wait a bit */ - - usleep(20*1000); - - /* Then power on again. All registers will be in their reset state. */ - - stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, 0); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_instantiate - * - * Description: - * Instantiate and configure the STMPE811 device driver to use the provided - * I2C or SPIdevice instance. - * - * Input Parameters: - * dev - An I2C or SPI driver instance - * config - Persistant board configuration data - * - * Returned Value: - * A non-zero handle is returned on success. This handle may then be used - * to configure the STMPE811 driver as necessary. A NULL handle value is - * returned on failure. - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_SPI -STMPE811_HANDLE stmpe811_instantiate(FAR struct spi_dev_s *dev, - FAR struct stmpe811_config_s *config) -#else -STMPE811_HANDLE stmpe811_instantiate(FAR struct i2c_dev_s *dev, - FAR struct stmpe811_config_s *config) -#endif -{ - FAR struct stmpe811_dev_s *priv; - uint8_t regval; - int ret; - - /* Allocate the device state structure */ - -#ifdef CONFIG_STMPE811_MULTIPLE - priv = (FAR struct stmpe811_dev_s *)kzalloc(sizeof(struct stmpe811_dev_s)); - if (!priv) - { - return NULL; - } - - /* And save the device structure in the list of STMPE811 so that we can find it later */ - - priv->flink = g_stmpe811list; - g_stmpe811list = priv; -#else - - /* Use the one-and-only STMPE811 driver instance */ - - priv = &g_stmpe811; -#endif - - /* Initialize the device state structure */ - - sem_init(&priv->exclsem, 0, 1); - priv->config = config; - -#ifdef CONFIG_STMPE811_SPI - priv->spi = dev; -#else - priv->i2c = dev; - - /* Set the I2C address and frequency. REVISIT: This logic would be - * insufficient if we share the I2C bus with any other devices that also - * modify the address and frequency. - */ - - I2C_SETADDRESS(dev, config->address, 7); - I2C_SETFREQUENCY(dev, config->frequency); -#endif - - /* Read and verify the STMPE811 chip ID */ - - ret = stmpe811_checkid(priv); - if (ret < 0) - { -#ifdef CONFIG_STMPE811_MULTIPLE - kfree(priv); -#endif - return NULL; - } - - /* Generate STMPE811 Software reset */ - - stmpe811_reset(priv); - - /* Configure the interrupt output pin to generate interrupts on high or low level. */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_CTRL); -#ifdef CONFIG_STMPE811_ACTIVELOW - regval &= ~INT_CTRL_INT_POLARITY; /* Pin polarity: Active low / falling edge */ -#else - regval |= INT_CTRL_INT_POLARITY; /* Pin polarity: Active high / rising edge */ -#endif -#ifdef CONFIG_STMPE811_EDGE - regval |= INT_CTRL_INT_TYPE; /* Edge interrupt */ -#else - regval &= ~INT_CTRL_INT_TYPE; /* Level interrupt */ -#endif - stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval); - - /* Attach the STMPE811 interrupt handler. */ - - config->attach(config, stmpe811_interrupt); - - /* Clear any pending interrupts */ - - stmpe811_putreg8(priv, STMPE811_INT_STA, INT_ALL); - config->clear(config); - config->enable(config, true); - - /* Enable global interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_CTRL); - regval |= INT_CTRL_GLOBAL_INT; - stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval); - - /* Return our private data structure as an opaque handle */ - - return (STMPE811_HANDLE)priv; -} - -/**************************************************************************** - * Name: stmpe811_getreg8 - * - * Description: - * Read from an 8-bit STMPE811 register - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_I2C -uint8_t stmpe811_getreg8(FAR struct stmpe811_dev_s *priv, uint8_t regaddr) -{ - /* 8-bit data read sequence: - * - * Start - I2C_Write_Address - STMPE811_Reg_Address - - * Repeated_Start - I2C_Read_Address - STMPE811_Read_Data - STOP - */ - - struct i2c_msg_s msg[2]; - uint8_t regval; - int ret; - - /* Setup 8-bit STMPE811 address write message */ - - msg[0].addr = priv->config->address; /* 7-bit address */ - msg[0].flags = 0; /* Write transaction, beginning with START */ - msg[0].buffer = ®addr; /* Transfer from this address */ - msg[0].length = 1; /* Send one byte following the address - * (no STOP) */ - - /* Set up the 8-bit STMPE811 data read message */ - - msg[1].addr = priv->config->address; /* 7-bit address */ - msg[1].flags = I2C_M_READ; /* Read transaction, beginning with Re-START */ - msg[1].buffer = ®val; /* Transfer to this address */ - msg[1].length = 1; /* Receive one byte following the address - * (then STOP) */ - - /* Perform the transfer */ - - ret = I2C_TRANSFER(priv->i2c, msg, 2); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return 0; - } - -#ifdef CONFIG_STMPE811_REGDEBUG - dbg("%02x->%02x\n", regaddr, regval); -#endif - return regval; -} -#endif - -/**************************************************************************** - * Name: stmpe811_putreg8 - * - * Description: - * Write a value to an 8-bit STMPE811 register - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_I2C -void stmpe811_putreg8(FAR struct stmpe811_dev_s *priv, - uint8_t regaddr, uint8_t regval) -{ - /* 8-bit data read sequence: - * - * Start - I2C_Write_Address - STMPE811_Reg_Address - STMPE811_Write_Data - STOP - */ - - struct i2c_msg_s msg; - uint8_t txbuffer[2]; - int ret; - -#ifdef CONFIG_STMPE811_REGDEBUG - dbg("%02x<-%02x\n", regaddr, regval); -#endif - - /* Setup to the data to be transferred. Two bytes: The STMPE811 register - * address followed by one byte of data. - */ - - txbuffer[0] = regaddr; - txbuffer[1] = regval; - - /* Setup 8-bit STMPE811 address write message */ - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = txbuffer; /* Transfer from this address */ - msg.length = 2; /* Send two byte following the address - * (then STOP) */ - - /* Perform the transfer */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - } -} -#endif - -/**************************************************************************** - * Name: stmpe811_getreg16 - * - * Description: - * Read 16-bits of data from an STMPE-11 register - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_I2C -uint16_t stmpe811_getreg16(FAR struct stmpe811_dev_s *priv, uint8_t regaddr) -{ - /* 16-bit data read sequence: - * - * Start - I2C_Write_Address - STMPE811_Reg_Address - - * Repeated_Start - I2C_Read_Address - STMPE811_Read_Data_1 - - * STMPE811_Read_Data_2 - STOP - */ - - - struct i2c_msg_s msg[2]; - uint8_t rxbuffer[2]; - int ret; - - /* Setup 8-bit STMPE811 address write message */ - - msg[0].addr = priv->config->address; /* 7-bit address */ - msg[0].flags = 0; /* Write transaction, beginning with START */ - msg[0].buffer = ®addr; /* Transfer from this address */ - msg[0].length = 1; /* Send one byte following the address - * (no STOP) */ - - /* Set up the 8-bit STMPE811 data read message */ - - msg[1].addr = priv->config->address; /* 7-bit address */ - msg[1].flags = I2C_M_READ; /* Read transaction, beginning with Re-START */ - msg[1].buffer = rxbuffer; /* Transfer to this address */ - msg[1].length = 2; /* Receive two bytes following the address - * (then STOP) */ - - /* Perform the transfer */ - - ret = I2C_TRANSFER(priv->i2c, msg, 2); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return 0; - } - -#ifdef CONFIG_STMPE811_REGDEBUG - dbg("%02x->%02x%02x\n", regaddr, rxbuffer[0], rxbuffer[1]); -#endif - return (uint16_t)rxbuffer[0] << 8 | (uint16_t)rxbuffer[1]; -} -#endif - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 */ - diff --git a/nuttx/drivers/input/stmpe811_gpio.c b/nuttx/drivers/input/stmpe811_gpio.c deleted file mode 100644 index b545828d1..000000000 --- a/nuttx/drivers/input/stmpe811_gpio.c +++ /dev/null @@ -1,454 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_gpio.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_GPIO_DISABLE) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_gpioinit - * - * Description: - * Initialize the GPIO interrupt subsystem - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static void stmpe811_gpioinit(FAR struct stmpe811_dev_s *priv) -{ - uint8_t regval; - - if ((priv->flags & STMPE811_FLAGS_GPIO_INITIALIZED) == 0) - { - /* Enable Clocking for GPIO */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~SYS_CTRL2_GPIO_OFF; - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Disable all GPIO interrupts */ - - stmpe811_putreg8(priv, STMPE811_GPIO_EN, 0); - - /* Enable global GPIO interrupts */ - -#ifndef CONFIG_STMPE811_GPIOINT_DISABLE - regval = stmpe811_getreg8(priv, STMPE811_INT_EN); - regval |= INT_GPIO; - stmpe811_putreg8(priv, STMPE811_INT_EN, regval); -#endif - - priv->flags |= STMPE811_FLAGS_GPIO_INITIALIZED; - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_gpioconfig - * - * Description: - * Configure an STMPE811 GPIO pin - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_gpioconfig(STMPE811_HANDLE handle, uint8_t pinconfig) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - uint8_t pinmask = (1 << pin); - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the pin is not already in use */ - - if ((priv->inuse & pinmask) != 0) - { - idbg("PIN%d is already in-use\n", pin); - sem_post(&priv->exclsem); - return -EBUSY; - } - - /* Make sure that the GPIO block has been initialized */ - - stmpe811_gpioinit(priv); - - /* Set the alternate function bit for the pin, making it a GPIO */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_AF); - regval |= pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval); - - /* Is the pin an input or an output? */ - - if ((pinconfig & STMPE811_GPIO_DIR) == STMPE811_GPIO_OUTPUT) - { - /* The pin is an output */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_DIR); - regval &= ~pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_DIR, regval); - - /* Set its initial output value */ - - stmpe811_gpiowrite(handle, pinconfig, - (pinconfig & STMPE811_GPIO_VALUE) != STMPE811_GPIO_ZERO); - } - else - { - /* It is an input */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_DIR); - regval |= pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_DIR, regval); - - /* Set up the falling edge detection */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_FE); - if ((pinconfig & STMPE811_GPIO_FALLING) != 0) - { - regval |= pinmask; - } - else - { - regval &= pinmask; - } - stmpe811_putreg8(priv, STMPE811_GPIO_FE, regval); - - /* Set up the rising edge detection */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_RE); - if ((pinconfig & STMPE811_GPIO_FALLING) != 0) - { - regval |= pinmask; - } - else - { - regval &= pinmask; - } - stmpe811_putreg8(priv, STMPE811_GPIO_RE, regval); - - /* Disable interrupts for now */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_EN); - regval &= ~pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_EN, regval); - } - - /* Mark the pin as 'in use' */ - - priv->inuse |= pinmask; - sem_post(&priv->exclsem); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_gpiowrite - * - * Description: - * Set or clear the GPIO output - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * value = true: write logic '1'; false: write logic '0; - * - * Returned Value: - * None - * - ****************************************************************************/ - -void stmpe811_gpiowrite(STMPE811_HANDLE handle, uint8_t pinconfig, bool value) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - idbg("sem_wait failed: %d\n", errno); - return; - } - - /* Are we setting or clearing outputs? */ - - if (value) - { - /* Set the output valu(s)e by writing to the SET register */ - - stmpe811_putreg8(priv, STMPE811_GPIO_SETPIN, (1 << pin)); - } - else - { - /* Clear the output value(s) by writing to the CLR register */ - - stmpe811_putreg8(priv, STMPE811_GPIO_CLRPIN, (1 << pin)); - } - - sem_post(&priv->exclsem); -} - -/**************************************************************************** - * Name: stmpe811_gpioread - * - * Description: - * Set or clear the GPIO output - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * value - The location to return the state of the GPIO pin - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_gpioread(STMPE811_HANDLE handle, uint8_t pinconfig, bool *value) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_MPSTA); - *value = ((regval & GPIO_PIN(pin)) != 0); - sem_post(&priv->exclsem); - return OK; -} - -/*********************************************************************************** - * Name: stmpe811_gpioattach - * - * Description: - * Attach to a GPIO interrupt input pin and enable interrupts on the pin. Using - * the value NULL for the handler address will disable interrupts from the pin and - * detach the handler. - * - * NOTE: Callbacks do not occur from an interrupt handler but rather from the - * context of the worker thread. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * handler - The handler that will be called when the interrupt occurs. - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is returned - * to indicate the nature of the failure. - * - ************************************************************************************/ - -#ifndef CONFIG_STMPE811_GPIOINT_DISABLE -int stmpe811_gpioattach(STMPE811_HANDLE handle, uint8_t pinconfig, - stmpe811_handler_t handler) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the GPIO interrupt system has been gpioinitialized */ - - stmpe811_gpioinit(priv); - - /* Set/clear the handler */ - - priv->handlers[pin] = handler; - - /* If an handler has provided, then we are enabling interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_EN); - if (handler) - { - /* Enable interrupts for this GPIO */ - - regval &= ~GPIO_PIN(pin); - } - else - { - /* Disable interrupts for this GPIO */ - - regval &= ~GPIO_PIN(pin); - } - stmpe811_putreg8(priv, STMPE811_GPIO_EN, regval); - - sem_post(&priv->exclsem); - return OK; -} -#endif - -/**************************************************************************** - * Name: stmpe811_gpioworker - * - * Description: - * Handle GPIO interrupt events (this function actually executes in the - * context of the worker thread). - * - ****************************************************************************/ - -#ifndef CONFIG_STMPE811_GPIOINT_DISABLE -void stmpe811_gpioworker(FAR struct stmpe811_dev_s *priv) -{ - uint8_t regval; - uint8_t pinmask; - int pin; - - /* Get the set of pending GPIO interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_INTSTA); - - /* Look at each pin */ - - for (pin = 0; pin < STMPE811_GPIO_NPINS; pin++) - { - pinmask = GPIO_INT(pin); - if ((regval & pinmask) != 0) - { - /* Check if we have a handler for this interrupt (there should - * be one) - */ - - if (priv->handlers[pin]) - { - /* Interrupt is pending... dispatch the interrupt to the - * callback - */ - - priv->handlers[pin](pin); - } - else - { - illdbg("No handler for PIN%d, GPIO_INTSTA: %02x\n", pin, regval); - } - - /* Clear the pending GPIO interrupt by writing a '1' to the - * pin position in the status register. - */ - - stmpe811_putreg8(priv, STMPE811_GPIO_INTSTA, pinmask); - } - } -} -#endif - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_GPIO_DISABLE */ - diff --git a/nuttx/drivers/input/stmpe811_temp.c b/nuttx/drivers/input/stmpe811_temp.c deleted file mode 100644 index 0fefd2069..000000000 --- a/nuttx/drivers/input/stmpe811_temp.c +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_temp.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_TEMP_DISABLE) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_tempinitialize - * - * Description: - * Configure the temperature sensor. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_tempinitialize(STMPE811_HANDLE handle) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t regval; - - /* Enable clocking for ADC and the temperature sensor */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~(SYS_CTRL2_TS_OFF | SYS_CTRL2_ADC_OFF); - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Enable the temperature sensor */ - - stmpe811_putreg8(priv, STMPE811_TEMP_CTRL, TEMP_CTRL_ENABLE); - - /* Aquire data enable */ - - stmpe811_putreg8(priv, STMPE811_TEMP_CTRL, (TEMP_CTRL_ACQ|TEMP_CTRL_ENABLE)); - - return OK; -} - -/**************************************************************************** - * Name: stmpe811_tempread - * - * Description: - * Configure the temperature sensor. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -uint16_t stmpe811_tempread(STMPE811_HANDLE handle) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint32_t temp = 0; - uint8_t temp1; - uint8_t temp2; - - /* Acquire data enable */ - - stmpe811_putreg8(priv, STMPE811_TEMP_CTRL, (TEMP_CTRL_ACQ|TEMP_CTRL_ENABLE)); - - /* Read the temperature */ - - temp1 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - temp2 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2+1); - - /* Scale the temperature (where Vio is assumed to be .33) */ - - temp = ((uint32_t)(temp1 & 3) << 8) | temp2; - temp = (uint32_t)((33 * temp * 100) / 751); - temp = (uint32_t)((temp + 5) / 10); - - return (uint16_t)temp; -} - -/**************************************************************************** - * Name: stmpe811_tempinterrupt - * - * Description: - * Configure the temperature sensor to sample the temperature periodically. - * Set the temperature threshold to generate an interrupt and notify - * to the client using the provide callback function pointer. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * threshold - The threshold temperature value - * direction - True: Generate an interrupt if the temperate exceeds the - * threshold value; False: Generate an interrupt if the - * temperature falls below the threshold value. - * callback - The client callback function that will be called when - * the termperature crosses the threshold. - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ -/* Not implemented */ - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_TEMP_DISABLE */ - diff --git a/nuttx/drivers/input/stmpe811_tsc.c b/nuttx/drivers/input/stmpe811_tsc.c deleted file mode 100644 index c7f8b473b..000000000 --- a/nuttx/drivers/input/stmpe811_tsc.c +++ /dev/null @@ -1,1144 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_tsc.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_TSC_DISABLE) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define Direction_IN 0x00 -#define Direction_OUT 0x01 - -#define Polarity_Low 0x00 -#define Polarity_High 0x04 -#define Type_Level 0x00 -#define Type_Edge 0x02 - -#define IO_IT_0 0x01 -#define IO_IT_1 0x02 -#define IO_IT_2 0x04 -#define IO_IT_3 0x08 -#define IO_IT_4 0x10 -#define IO_IT_5 0x20 -#define IO_IT_6 0x40 -#define IO_IT_7 0x80 -#define ALL_IT 0xFF -#define IOE_JOY_IT (uint8_t)(IO_IT_3 | IO_IT_4 | IO_IT_5 | IO_IT_6 | IO_IT_7) -#define IOE_TS_IT (uint8_t)(IO_IT_0 | IO_IT_1 | IO_IT_2) -#define IOE_INMEMS_IT (uint8_t)(IO_IT_2 | IO_IT_3) - -#define EDGE_FALLING 0x01 -#define EDGE_RISING 0x02 - -#define TIMEOUT_MAX 0x3000 /*nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the STMPE811 - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for STMPE811 data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_STMPE811_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: stmpe811_sample - * - * Description: - * Check if touchscreen sample data is available now and, if so, return - * the sample data. This is part of the stmpe811_read logic. - * - * Assumption: - * Pre-emption is disable to prevent the worker thread from running. - * Otherwise, sampled data may continue to change. - * - ****************************************************************************/ - -static int stmpe811_sample(FAR struct stmpe811_dev_s *priv, - FAR struct stmpe811_sample_s *sample) -{ - int ret = -EAGAIN; - - /* Is there new STMPE811 sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct stmpe811_sample_s)); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* The sampling logic has detected pen-up in some condition other - * than CONTACT_NONE. Set the next state to CONTACT_NONE: Further - * pen-down reports will be ignored. Increment the ID so that - * next contact ID will be unique - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* The sampling logic has detected pen-up in some condition other - * than CONTACT_MOVE. Set the next state to CONTACT_MOVE: Further - * samples collected while the pen is down will reported as movement - * events. - */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - return ret; -} - -/**************************************************************************** - * Name: stmpe811_waitsample - * - * Description: - * Wait for a sample to become available (this is really part of the - * stmpe811_read logic). - * - ****************************************************************************/ - -static inline int stmpe811_waitsample(FAR struct stmpe811_dev_s *priv, - FAR struct stmpe811_sample_s *sample) -{ - int ret; - - /* Disable pre-emption to prevent the worker thread from running - * asynchronously. - */ - - sched_lock(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->exclsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is availble. - */ - - while (stmpe811_sample(priv, sample) < 0) - { - /* Wait for a change in the STMPE811 state */ - - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - /* When we are re-awakened, pre-emption will again be disabled */ - - if (ret < 0) - { -#ifdef CONFIG_DEBUG - // Sample the errno (debug output could change it) - - int errval = errno; - - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - idbg("ERROR: sem_wait failed: %d\n", errval); - DEBUGASSERT(errval == EINTR); -#endif - ret = -EINTR; - goto errout; - } - } - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->exclsem); - -errout: - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the STMPE811 for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_open - * - * Description: - * Standard character driver open method. - * - ****************************************************************************/ - -static int stmpe811_open(FAR struct file *filep) -{ -#ifdef CONFIG_STMPE811_REFCNT - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - uint8_t tmp; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->exclsem); - return ret; -#else - return OK; -#endif -} - -/**************************************************************************** - * Name: stmpe811_close - * - * Description: - * Standard character driver close method. - * - ****************************************************************************/ - -static int stmpe811_close(FAR struct file *filep) -{ -#ifdef CONFIG_STMPE811_REFCNT - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->exclsem); -#endif - return OK; -} - -/**************************************************************************** - * Name: stmpe811_read - * - * Description: - * Standard character driver read method. - * - ****************************************************************************/ - -static ssize_t stmpe811_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - FAR struct touch_sample_s *report; - struct stmpe811_sample_s sample; - int ret; - - ivdbg("len=%d\n", len); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = stmpe811_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = stmpe811_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - goto errout; - } - } - - /* In any event, we now have sampled STMPE811 data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = sample.id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - report->point[0].pressure = sample.z; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_ioctl - * - * Description: - * Standard character driver ioctl method. - * -****************************************************************************/ - -static int stmpe811_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = I2C_SETFREQUENCY(priv->i2c, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_poll - * - * Description: - * Standard character driver poll method. - * - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int stmpe811_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - int ret; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - idbg("ERROR: Missing POLLIN: revents: %08x\n", fds->revents); - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_STMPE811_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_STMPE811_NPOLLWAITERS) - { - idbg("ERROR: No availabled slot found: %d\n", i); - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - stmpe811_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->exclsem); - return ret; -} -#endif - -/**************************************************************************** - * Name: stmpe811_timeoutworker - * - * Description: - * A timer has expired without receiving a pen up event. Check again. - * - ****************************************************************************/ - -static void stmpe811_timeoutworker(FAR void *arg) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)arg; - - DEBUGASSERT(priv); - - /* Treat the timeout just like an interrupt occurred */ - - stmpe811_tscworker(priv, stmpe811_getreg8(priv, STMPE811_INT_STA)); -} - -/**************************************************************************** - * Name: stmpe811_timeout - * - * Description: - * A timer has expired without receiving a pen up event. Schedule work - * to check again. - * - ****************************************************************************/ - -static void stmpe811_timeout(int argc, uint32_t arg1, ...) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)((uintptr_t)arg1); - int ret; - - /* Are we still stuck in the pen down state? */ - - if (priv->sample.contact == CONTACT_MOVE || - priv->sample.contact == CONTACT_MOVE) - { - /* Yes... is the worker thread available? If not, then apparently - * we have work already pending? - */ - - if (work_available(&priv->timeout)) - { - /* Yes.. Transfer processing to the worker thread. Since STMPE811 - * interrupts are disabled while the work is pending, no special - * action should be required to protect the work queue. - */ - - ret = work_queue(HPWORK, &priv->timeout, stmpe811_timeoutworker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - } - } -} - -/**************************************************************************** - * Name: stmpe811_tscinitialize - * - * Description: - * Initialize the touchscreen controller. This is really a part of the - * stmpe811_register logic, - * - ****************************************************************************/ - -static inline void stmpe811_tscinitialize(FAR struct stmpe811_dev_s *priv) -{ - uint8_t regval; - - ivdbg("Initializing touchscreen controller\n"); - - /* Enable TSC and ADC functions */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~(SYS_CTRL2_TSC_OFF | SYS_CTRL2_ADC_OFF); - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Enable the TSC global interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_EN); - regval |= (uint32_t)(INT_TOUCH_DET | INT_FIFO_TH | INT_FIFO_OFLOW); - stmpe811_putreg8(priv, STMPE811_INT_EN, regval); - - /* Select Sample Time, bit number and ADC Reference */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL1, priv->config->ctrl1); - - /* Wait for 20 ms */ - - up_mdelay(20); - - /* Select the ADC clock speed */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL2, priv->config->ctrl2); - - /* Select TSC pins in non-GPIO mode (AF=0) */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_AF); - regval &= ~(uint8_t)TSC_PIN_SET; - stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval); - - /* Select 2 nF filter capacitor */ - - stmpe811_putreg8(priv, STMPE811_TSC_CFG, - (TSC_CFG_AVE_CTRL_4SAMPLES | TSC_CFG_TOUCH_DELAY_500US | TSC_CFG_SETTLING_500US)); - - /* Select single point reading */ - - stmpe811_putreg8(priv, STMPE811_FIFO_TH, 1); - - /* Reset and clear the FIFO. */ - - stmpe811_putreg8(priv, STMPE811_FIFO_STA, FIFO_STA_FIFO_RESET); - stmpe811_putreg8(priv, STMPE811_FIFO_STA, 0); - - /* set the data format for Z value: 7 fractional part and 1 whole part */ - - stmpe811_putreg8(priv, STMPE811_TSC_FRACTIONZ, 0x01); - - /* Set the driving capability of the device for TSC pins: 50mA */ - - stmpe811_putreg8(priv, STMPE811_TSC_IDRIVE, TSC_IDRIVE_50MA); - - /* Enable the TSC. Use no tracking index, touch-screen controller - * operation mode (XYZ). - */ - - stmpe811_putreg8(priv, STMPE811_TSC_CTRL, TSC_CTRL_EN); - - /* Clear all the status pending bits */ - - stmpe811_putreg8(priv, STMPE811_INT_STA, INT_ALL); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_register - * - * Description: - * Enable TSC functionality. GPIO4-7 must be available. This function - * will register the touchsceen driver as /dev/inputN where N is the minor - * device number - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_register - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_register(STMPE811_HANDLE handle, int minor) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - char devname[DEV_NAMELEN]; - int ret; - - ivdbg("handle=%p minor=%d\n", handle, minor); - DEBUGASSERT(priv); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("ERROR: sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the pins (4-7) need by the TSC are not already in use */ - - if ((priv->inuse & TSC_PIN_SET) != 0) - { - idbg("ERROR: TSC pins is already in-use: %02x\n", priv->inuse); - sem_post(&priv->exclsem); - return -EBUSY; - } - - /* Initialize the TS structure fields to their default values */ - - priv->minor = minor; - priv->penchange = false; - priv->threshx = 0; - priv->threshy = 0; - - /* Create a timer for catching missed pen up conditions */ - - priv->wdog = wd_create(); - if (!priv->wdog) - { - idbg("ERROR: Failed to create a watchdog\n", errno); - sem_post(&priv->exclsem); - return -ENOSPC; - } - - /* Register the character driver */ - - snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ret = register_driver(devname, &g_stmpe811fops, 0666, priv); - if (ret < 0) - { - idbg("ERROR: Failed to register driver %s: %d\n", devname, ret); - sem_post(&priv->exclsem); - return ret; - } - - /* Initialize the touchscreen controller */ - - stmpe811_tscinitialize(priv); - - /* Inidicate that the touchscreen controller was successfully initialized */ - - priv->inuse |= TSC_PIN_SET; /* Pins 4-7 are now in-use */ - priv->flags |= STMPE811_FLAGS_TSC_INITIALIZED; /* TSC function is initialized */ - sem_post(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_tscworker - * - * Description: - * This function is called to handle a TSC interrupt. It is not really - * an interrupt handle because it is called from the STMPE811 "bottom half" - * logic that runs on the worker thread. - * - ****************************************************************************/ - -void stmpe811_tscworker(FAR struct stmpe811_dev_s *priv, uint8_t intsta) -{ - FAR struct stmpe811_config_s *config; /* Convenience pointer */ - bool pendown; /* true: pend is down */ - uint16_t xdiff; /* X difference used in thresholding */ - uint16_t ydiff; /* Y difference used in thresholding */ - uint16_t x; /* X position */ - uint16_t y; /* Y position */ - - ASSERT(priv != NULL); - - /* Cancel the missing pen up timer */ - - (void)wd_cancel(priv->wdog); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Check for pen up or down from the TSC_STA ibit n the STMPE811_TSC_CTRL register. */ - - pendown = (stmpe811_getreg8(priv, STMPE811_TSC_CTRL) & TSC_CTRL_TSC_STA) != 0; - - /* Handle the change from pen down to pen up */ - - if (!pendown) - { - /* The pen is up.. reset thresholding variables. FIFOs will read zero if - * there is no data available (hence the choice of (0,0)) - */ - - priv->threshx = 0; - priv->threshy = 0; - - /* Ignore the interrupt if the pen was already up (CONTACT_NONE == pen up and - * already reported; CONTACT_UP == pen up, but not reported) - */ - - if (priv->sample.contact == CONTACT_NONE || - priv->sample.contact == CONTACT_UP) - { - goto ignored; - } - - /* A pen-down to up transition has been detected. CONTACT_UP indicates the - * initial loss of contzt. The state will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* The pen is down... check for data in the FIFO */ - - else if ((intsta & (INT_FIFO_TH|INT_FIFO_OFLOW)) != 0) - { - /* Read the next x and y positions from the FIFO. */ - -#ifdef CONFIG_STMPE811_SWAPXY - x = stmpe811_getreg16(priv, STMPE811_TSC_DATAX); - y = stmpe811_getreg16(priv, STMPE811_TSC_DATAY); -#else - x = stmpe811_getreg16(priv, STMPE811_TSC_DATAY); - y = stmpe811_getreg16(priv, STMPE811_TSC_DATAX); -#endif - - /* If we have not yet processed the last pen up event, then we - * cannot handle this pen down event. We will have to discard it. That - * should be okay because there will be another FIFO event right behind - * this one. Other kinds of data overruns are not harmful. - * - * Hmm.. a better design might be to disable FIFO interrupts when we - * detect pen up. Then re-enable them when CONTACT_UP is reported. - * That would save processing interrupts just to discard the data. - */ - - if (priv->sample.contact == CONTACT_UP) - { - /* We have not closed the loop on the last touch ... don't report - * anything. - */ - - goto ignored; - } - - /* Perform a thresholding operation so that the results will be more stable. - * If the difference from the last sample is small, then ignore the event. - * REVISIT: Should a large change in pressure also generate a event? - */ - - xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x); - ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y); - - if (xdiff < CONFIG_STMPE811_THRESHX && ydiff < CONFIG_STMPE811_THRESHY) - { - /* Little or no change in either direction ... don't report anything. */ - - goto ignored; - } - - /* When we see a big difference, snap to the new x/y thresholds */ - - priv->threshx = x; - priv->threshy = y; - - /* Update the x/y position in the sample data */ - - priv->sample.x = priv->threshx; - priv->sample.y = priv->threshy; - - /* Update the Z pressure index */ - - priv->sample.z = stmpe811_getreg8(priv, STMPE811_TSC_DATAZ); - priv->sample.valid = true; - - /* If this is the first (acknowledged) pen down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - - /* Pen down, but no data in FIFO */ - - else - { - /* Ignore the interrupt... wait until there is data in the FIFO */ - - goto ignored; - } - - /* We get here if (1) we just went from a pen down to a pen up state OR (2) - * We just get a measurement from the FIFO in a pen down state. Indicate - * the availability of new sample data for this ID. - */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that new STMPE811 data is available */ - - stmpe811_notify(priv); - - /* If we think that the pend is still down, the start/re-start the pen up - * timer. - */ - -ignored: - if (priv->sample.contact == CONTACT_MOVE || - priv->sample.contact == CONTACT_MOVE) - { - (void)wd_start(priv->wdog, STMPE811_PENUP_TICKS, stmpe811_timeout, - 1, (uint32_t)((uintptr_t)priv)); - } - - /* Reset and clear all data in the FIFO */ - - stmpe811_putreg8(priv, STMPE811_FIFO_STA, FIFO_STA_FIFO_RESET); - stmpe811_putreg8(priv, STMPE811_FIFO_STA, 0); -} - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_TSC_DISABLE */ - diff --git a/nuttx/drivers/input/tsc2007.c b/nuttx/drivers/input/tsc2007.c deleted file mode 100644 index 163118b95..000000000 --- a/nuttx/drivers/input/tsc2007.c +++ /dev/null @@ -1,1336 +0,0 @@ -/**************************************************************************** - * drivers/input/tsc2007.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "1.2V to 3.6V, 12-Bit, Nanopower, 4-Wire Micro TOUCH SCREEN CONTROLLER - * with I2C Interface," SBAS405A March 2007, Revised, March 2009, Texas - * Instruments Incorporated - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/* The TSC2007 is an analog interface circuit for a human interface touch - * screen device. All peripheral functions are controlled through the command - * byte and onboard state machines. - */ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "tsc2007.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* Reference counting is partially implemented, but not needed in the - * current design. - */ - -#undef CONFIG_TSC2007_REFCNT - -/* I don't think that it is necessary to activate the converters before - * making meaurements. However, I will keep this functionality enabled - * until I have a change to prove that that activation is unnecessary. - */ - -#undef CONFIG_TSC2007_ACTIVATE -#define CONFIG_TSC2007_ACTIVATE 1 - -/* Driver support ***********************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* Commands *****************************************************************/ - -#define TSC2007_SETUP (TSC2007_CMD_FUNC_SETUP) -#ifdef CONFIG_TSC2007_8BIT -# define TSC2007_ACTIVATE_Y (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YON) -# define TSC2007_MEASURE_Y (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YPOS) -# define TSC2007_ACTIVATE_X (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XON) -# define TSC2007_MEASURE_X (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XPOS) -# define TSC2007_ACTIVATE_Z (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YXON) -# define TSC2007_MEASURE_Z1 (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z1POS) -# define TSC2007_MEASURE_Z2 (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z2POS) -# define TSC2007_ENABLE_PENIRQ (TSC2007_CMD_8BIT | TSC2007_CMD_PWRDN_IRQEN) -#else -# define TSC2007_ACTIVATE_Y (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YON) -# define TSC2007_MEASURE_Y (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YPOS) -# define TSC2007_ACTIVATE_X (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XON) -# define TSC2007_MEASURE_X (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XPOS) -# define TSC2007_ACTIVATE_Z (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YXON) -# define TSC2007_MEASURE_Z1 (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z1POS) -# define TSC2007_MEASURE_Z2 (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z2POS) -# define TSC2007_ENABLE_PENIRQ (TSC2007_CMD_12BIT | TSC2007_CMD_PWRDN_IRQEN) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This describes the state of one contact */ - -enum tsc2007_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one TSC2007 sample */ - -struct tsc2007_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum tsc2007_contact_e) */ - bool valid; /* True: x,y,pressure contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ - uint16_t pressure; /* Calculated pressure */ -}; - -/* This structure describes the state of one TSC2007 driver instance */ - -struct tsc2007_dev_s -{ -#ifdef CONFIG_TSC2007_MULTIPLE - FAR struct tsc2007_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif -#ifdef CONFIG_TSC2007_REFCNT - uint8_t crefs; /* Number of times the device has been opened */ -#endif - uint8_t nwaiters; /* Number of threads waiting for TSC2007 data */ - uint8_t id; /* Current touch point ID */ - volatile bool penchange; /* An unreported event is buffered */ - sem_t devsem; /* Manages exclusive access to this structure */ - sem_t waitsem; /* Used to wait for the availability of data */ - - FAR struct tsc2007_config_s *config; /* Board configuration data */ - FAR struct i2c_dev_s *i2c; /* Saved I2C driver instance */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - struct tsc2007_sample_s sample; /* Last sampled touch point data */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_TSC2007_NPOLLWAITERS]; -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void tsc2007_notify(FAR struct tsc2007_dev_s *priv); -static int tsc2007_sample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample); -static int tsc2007_waitsample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample); -#ifdef CONFIG_TSC2007_ACTIVATE -static int tsc2007_activate(FAR struct tsc2007_dev_s *priv, uint8_t cmd); -#endif -static int tsc2007_transfer(FAR struct tsc2007_dev_s *priv, uint8_t cmd); -static void tsc2007_worker(FAR void *arg); -static int tsc2007_interrupt(int irq, FAR void *context); - -/* Character driver methods */ - -static int tsc2007_open(FAR struct file *filep); -static int tsc2007_close(FAR struct file *filep); -static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len); -static int tsc2007_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int tsc2007_poll(FAR struct file *filep, struct pollfd *fds, bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This the the vtable that supports the character driver interface */ - -static const struct file_operations tsc2007_fops = -{ - tsc2007_open, /* open */ - tsc2007_close, /* close */ - tsc2007_read, /* read */ - 0, /* write */ - 0, /* seek */ - tsc2007_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , tsc2007_poll /* poll */ -#endif -}; - -/* If only a single TSC2007 device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_TSC2007_MULTIPLE -static struct tsc2007_dev_s g_tsc2007; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct tsc2007_dev_s *g_tsc2007list; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: tsc2007_notify - ****************************************************************************/ - -static void tsc2007_notify(FAR struct tsc2007_dev_s *priv) -{ -#ifndef CONFIG_DISABLE_POLL - int i; -#endif - - /* If there are threads waiting for read data, then signal one of them - * that the read data is available. - */ - - if (priv->nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the TSC2007 - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for TSC2007 data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_TSC2007_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: tsc2007_sample - ****************************************************************************/ - -static int tsc2007_sample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample) -{ - irqstate_t flags; - int ret = -EAGAIN; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - */ - - flags = irqsave(); - - /* Is there new TSC2007 sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct tsc2007_sample_s )); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* Next.. no contact. Increment the ID so that next contact ID - * will be unique. X/Y positions are no longer valid. - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* First report -- next report will be a movement */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - irqrestore(flags); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_waitsample - ****************************************************************************/ - -static int tsc2007_waitsample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample) -{ - irqstate_t flags; - int ret; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - * - * In addition, we will also disable pre-emption to prevent other threads - * from getting control while we muck with the semaphores. - */ - - sched_lock(); - flags = irqsave(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->devsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is availble. - */ - - while (tsc2007_sample(priv, sample) < 0) - { - /* Wait for a change in the TSC2007 state */ - - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - if (ret < 0) - { - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - DEBUGASSERT(errno == EINTR); - ret = -EINTR; - goto errout; - } - } - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->devsem); - -errout: - /* Then re-enable interrupts. We might get interrupt here and there - * could be a new sample. But no new threads will run because we still - * have pre-emption disabled. - */ - - irqrestore(flags); - - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the TSC2007 for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_activate - ****************************************************************************/ - -#ifdef CONFIG_TSC2007_ACTIVATE -static int tsc2007_activate(FAR struct tsc2007_dev_s *priv, uint8_t cmd) -{ - struct i2c_msg_s msg; - uint8_t data; - int ret; - - /* Send the setup command (with no ACK) followed by the A/D converter - * activation command (ACKed). - */ - - data = TSC2007_SETUP; - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = &data; /* Transfer from this address */ - msg.length = 1; /* Send one byte following the address */ - - /* Ignore errors from the setup command (because it is not ACKed) */ - - (void)I2C_TRANSFER(priv->i2c, &msg, 1); - - /* Now activate the A/D converter */ - - data = cmd; - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = &data; /* Transfer from this address */ - msg.length = 1; /* Send one byte following the address */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - } - return ret; -} -#else -# define tsc2007_activate(p,c) -#endif - -/**************************************************************************** - * Name: tsc2007_transfer - ****************************************************************************/ - -static int tsc2007_transfer(FAR struct tsc2007_dev_s *priv, uint8_t cmd) -{ - struct i2c_msg_s msg; - uint8_t data12[2]; - int ret; - - /* "A conversion/write cycle begins when the master issues the address - * byte containing the slave address of the TSC2007, with the eighth bit - * equal to a 0 (R/W = 0)... Once the eighth bit has been received... - * the TSC2007 issues an acknowledge. - * - * "When the master receives the acknowledge bit from the TSC2007, the - * master writes the command byte to the slave... After the command byte - * is received by the slave, the slave issues another acknowledge bit. - * The master then ends the write cycle by issuing a repeated START or a - * STOP condition... - */ - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = &cmd; /* Transfer from this address */ - msg.length = 1; /* Send one byte following the address */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return ret; - } - - /* "The input multiplexer channel for the A/D converter is selected when - * bits C3 through C0 are clocked in. If the selected channel is an X-,Y-, - * or Z-position measurement, the appropriate drivers turn on once the - * acquisition period begins. - * - * "... the input sample acquisition period starts on the falling edge of - * SCL when the C0 bit of the command byte has been latched, and ends - * when a STOP or repeated START condition has been issued. A/D conversion - * starts immediately after the acquisition period... - * - * "For best performance, the I2C bus should remain in an idle state while - * an A/D conversion is taking place. ... The master should wait for at - * least 10ms before attempting to read data from the TSC2007... - */ - - usleep(10*1000); - - /* "Data access begins with the master issuing a START condition followed - * by the address byte ... with R/W = 1. - * - * "When the eighth bit has been received and the address matches, the - * slave issues an acknowledge. The first byte of serial data then follows - * (D11-D4, MSB first). - * - * "After the first byte has been sent by the slave, it releases the SDA line - * for the master to issue an acknowledge. The slave responds with the - * second byte of serial data upon receiving the acknowledge from the master - * (D3-D0, followed by four 0 bits). The second byte is followed by a NOT - * acknowledge bit (ACK = 1) from the master to indicate that the last - * data byte has been received... - */ - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = I2C_M_READ; /* Read transaction, beginning with START */ - msg.buffer = data12; /* Transfer to this address */ - msg.length = 2; /* Read two bytes following the address */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return ret; - } - - /* Get the MS 8 bits from the first byte and the remaining LS 4 bits from - * the second byte. The valid range of data is then from 0 to 4095 with - * the LSB unit corresponding to Vref/4096. - */ - - ret = (unsigned int)data12[0] << 4 | (unsigned int)data12[1] >> 4; - ivdbg("data: 0x%04x\n", ret); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_worker - ****************************************************************************/ - -static void tsc2007_worker(FAR void *arg) -{ - FAR struct tsc2007_dev_s *priv = (FAR struct tsc2007_dev_s *)arg; - FAR struct tsc2007_config_s *config; /* Convenience pointer */ - bool pendown; /* true: pend is down */ - uint16_t x; /* X position */ - uint16_t y; /* Y position */ - uint16_t z1; /* Z1 position */ - uint16_t z2; /* Z2 position */ - uint32_t pressure; /* Measured pressure */ - - ASSERT(priv != NULL); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Check for pen up or down by reading the PENIRQ GPIO. */ - - pendown = config->pendown(config); - - /* Handle the change from pen down to pen up */ - - if (!pendown) - { - /* Ignore the interrupt if the pen was already down (CONTACT_NONE == pen up and - * already reported. CONTACT_UP == pen up, but not reported) - */ - - if (priv->sample.contact == CONTACT_NONE) - { - goto errout; - } - } - - /* It is a pen down event. If the last loss-of-contact event has not been - * processed yet, then we have to ignore the pen down event (or else it will - * look like a drag event) - */ - - else if (priv->sample.contact == CONTACT_UP) - { - goto errout; - } - else - { - /* Handle all pen down events. First, sample X, Y, Z1, and Z2 values. - * - * "A resistive touch screen operates by applying a voltage across a - * resistor network and measuring the change in resistance at a given - * point on the matrix where the screen is touched by an input (stylus, - * pen, or finger). The change in the resistance ratio marks the location - * on the touch screen. - * - * "The 4-wire touch screen panel works by applying a voltage across the - * vertical or horizontal resistive network. The A/D converter converts - * the voltage measured at the point where the panel is touched. A measurement - * of the Y position of the pointing device is made by connecting the X+ - * input to a data converter chip, turning on the Y+ and Y– drivers, and - * digitizing the voltage seen at the X+ input ..." - * - * "... it is recommended that whenever the host writes to the TSC2007, the - * master processor masks the interrupt associated to PENIRQ. This masking - * prevents false triggering of interrupts when the PENIRQ line is disabled - * in the cases previously listed." - */ - - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_X); - y = tsc2007_transfer(priv, TSC2007_MEASURE_Y); - - - /* "Voltage is then applied to the other axis, and the A/D converter - * converts the voltage representing the X position on the screen. This - * process provides the X and Y coordinates to the associated processor." - */ - - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_Y); - x = tsc2007_transfer(priv, TSC2007_MEASURE_X); - - /* "... To determine pen or finger touch, the pressure of the touch must be - * determined. ... There are several different ways of performing this - * measurement. The TSC2007 supports two methods. The first method requires - * knowing the X-plate resistance, the measurement of the X-position, and two - * additional cross panel measurements (Z2 and Z1) of the touch screen." - * - * Rtouch = Rxplate * (X / 4096)* (Z2/Z1 - 1) - * - * "The second method requires knowing both the X-plate and Y-plate - * resistance, measurement of X-position and Y-position, and Z1 ..." - * - * Rtouch = Rxplate * (X / 4096) * (4096/Z1 - 1) - Ryplate * (1 - Y/4096) - * - * Read Z1 and Z2 values. - */ - - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_Z); - z1 = tsc2007_transfer(priv, TSC2007_MEASURE_Z1); - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_Z); - z2 = tsc2007_transfer(priv, TSC2007_MEASURE_Z2); - - /* Power down ADC and enable PENIRQ */ - - (void)tsc2007_transfer(priv, TSC2007_ENABLE_PENIRQ); - - /* Now calculate the pressure using the first method, reduced to: - * - * Rtouch = X * Rxplate *(Z2 - Z1) * / Z1 / 4096 - */ - - if (z1 == 0) - { - idbg("Z1 zero\n"); - pressure = 0; - } - else - { - pressure = (x * config->rxplate * (z2 - z1)) / z1; - pressure = (pressure + 2048) >> 12; - - ivdbg("Position: (%d,%4d) pressure: %u z1/2: (%d,%d)\n", - x, y, pressure, z1, z2); - - /* Ignore out of range caculcations */ - - if (pressure > 0x0fff) - { - idbg("Dropped out-of-range pressure: %d\n", pressure); - pressure = 0; - } - } - - /* Save the measurements */ - - priv->sample.x = x; - priv->sample.y = y; - priv->sample.pressure = pressure; - priv->sample.valid = true; - } - - /* Note the availability of new measurements */ - - if (pendown) - { - /* If this is the first (acknowledged) pend down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - else /* if (priv->sample.contact != CONTACT_NONE) */ - { - /* The pen is up. NOTE: We know from a previous test, that this is a - * loss of contact condition. This will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* Indicate the availability of new sample data for this ID */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that nes TSC2007 data is available */ - - tsc2007_notify(priv); - - /* Exit, re-enabling TSC2007 interrupts */ - -errout: - config->enable(config, true); -} - -/**************************************************************************** - * Name: tsc2007_interrupt - ****************************************************************************/ - -static int tsc2007_interrupt(int irq, FAR void *context) -{ - FAR struct tsc2007_dev_s *priv; - FAR struct tsc2007_config_s *config; - int ret; - - /* Which TSC2007 device caused the interrupt? */ - -#ifndef CONFIG_TSC2007_MULTIPLE - priv = &g_tsc2007; -#else - for (priv = g_tsc2007list; - priv && priv->configs->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts */ - - config->enable(config, false); - - /* Transfer processing to the worker thread. Since TSC2007 interrupts are - * disabled while the work is pending, no special action should be required - * to protected the work queue. - */ - - DEBUGASSERT(priv->work.worker == NULL); - ret = work_queue(HPWORK, &priv->work, tsc2007_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return OK; -} - -/**************************************************************************** - * Name: tsc2007_open - ****************************************************************************/ - -static int tsc2007_open(FAR struct file *filep) -{ -#ifdef CONFIG_TSC2007_REFCNT - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - uint8_t tmp; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->devsem); - return ret; -#else - return OK; -#endif -} - -/**************************************************************************** - * Name: tsc2007_close - ****************************************************************************/ - -static int tsc2007_close(FAR struct file *filep) -{ -#ifdef CONFIG_TSC2007_REFCNT - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->devsem); -#endif - return OK; -} - -/**************************************************************************** - * Name: tsc2007_read - ****************************************************************************/ - -static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - FAR struct touch_sample_s *report; - struct tsc2007_sample_s sample; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = tsc2007_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = tsc2007_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - goto errout; - } - } - - /* In any event, we now have sampled TSC2007 data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = priv->id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - report->point[0].pressure = sample.pressure; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else - { - if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - - /* A pressure measurement of zero means that pressure is not available */ - - if (report->point[0].pressure != 0) - { - report->point[0].flags |= TOUCH_PRESSURE_VALID; - } - } - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name:tsc2007_ioctl - ****************************************************************************/ - -static int tsc2007_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETCALIB: /* arg: Pointer to int calibration value */ - { - FAR int *ptr = (FAR int *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->rxplate = *ptr; - } - break; - - case TSIOC_GETCALIB: /* arg: Pointer to int calibration value */ - { - FAR int *ptr = (FAR int *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->rxplate; - } - break; - - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = I2C_SETFREQUENCY(priv->i2c, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int tsc2007_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - int ret; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - idbg("Missing POLLIN: revents: %08x\n", fds->revents); - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_TSC2007_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_TSC2007_NPOLLWAITERS) - { - idbg("No availabled slot found: %d\n", i); - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - tsc2007_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->devsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: tsc2007_register - * - * Description: - * Configure the TSC2007 to use the provided I2C device instance. This - * will register the driver as /dev/inputN where N is the minor device - * number - * - * Input Parameters: - * dev - An I2C driver instance - * config - Persistant board configuration data - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int tsc2007_register(FAR struct i2c_dev_s *dev, - FAR struct tsc2007_config_s *config, int minor) -{ - FAR struct tsc2007_dev_s *priv; - char devname[DEV_NAMELEN]; -#ifdef CONFIG_TSC2007_MULTIPLE - irqstate_t flags; -#endif - int ret; - - ivdbg("dev: %p minor: %d\n", dev, minor); - - /* Debug-only sanity checks */ - - DEBUGASSERT(dev != NULL && config != NULL && minor >= 0 && minor < 100); - DEBUGASSERT((config->address & 0xfc) == 0x48); - DEBUGASSERT(config->attach != NULL && config->enable != NULL && - config->clear != NULL && config->pendown != NULL); - - /* Create and initialize a TSC2007 device driver instance */ - -#ifndef CONFIG_TSC2007_MULTIPLE - priv = &g_tsc2007; -#else - priv = (FAR struct tsc2007_dev_s *)kmalloc(sizeof(struct tsc2007_dev_s)); - if (!priv) - { - idbg("kmalloc(%d) failed\n", sizeof(struct tsc2007_dev_s)); - return -ENOMEM; - } -#endif - - /* Initialize the TSC2007 device driver instance */ - - memset(priv, 0, sizeof(struct tsc2007_dev_s)); - priv->i2c = dev; /* Save the I2C device handle */ - priv->config = config; /* Save the board configuration */ - sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ - sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ - - /* Set the I2C frequency (saving the actual frequency) */ - - config->frequency = I2C_SETFREQUENCY(dev, config->frequency); - - /* Set the I2C address and address size */ - - ret = I2C_SETADDRESS(dev, config->address, 7); - if (ret < 0) - { - idbg("I2C_SETADDRESS failed: %d\n", ret); - goto errout_with_priv; - } - - /* Make sure that interrupts are disabled */ - - config->clear(config); - config->enable(config, false); - - /* Attach the interrupt handler */ - - ret = config->attach(config, tsc2007_interrupt); - if (ret < 0) - { - idbg("Failed to attach interrupt\n"); - goto errout_with_priv; - } - - /* Power down the ADC and enable PENIRQ. This is the normal state while - * waiting for a touch event. - */ - - ret = tsc2007_transfer(priv, TSC2007_ENABLE_PENIRQ); - if (ret < 0) - { - idbg("tsc2007_transfer failed: %d\n", ret); - goto errout_with_priv; - } - - /* Register the device as an input device */ - - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ivdbg("Registering %s\n", devname); - - ret = register_driver(devname, &tsc2007_fops, 0666, priv); - if (ret < 0) - { - idbg("register_driver() failed: %d\n", ret); - goto errout_with_priv; - } - - /* If multiple TSC2007 devices are supported, then we will need to add - * this new instance to a list of device instances so that it can be - * found by the interrupt handler based on the recieved IRQ number. - */ - -#ifdef CONFIG_TSC2007_MULTIPLE - flags = irqsave(); - priv->flink = g_tsc2007list; - g_tsc2007list = priv; - irqrestore(flags); -#endif - - /* Schedule work to perform the initial sampling and to set the data - * availability conditions. - */ - - ret = work_queue(HPWORK, &priv->work, tsc2007_worker, priv, 0); - if (ret != 0) - { - idbg("Failed to queue work: %d\n", ret); - goto errout_with_priv; - } - - /* And return success (?) */ - - return OK; - -errout_with_priv: - sem_destroy(&priv->devsem); -#ifdef CONFIG_TSC2007_MULTIPLE - kfree(priv); -#endif - return ret; -} diff --git a/nuttx/drivers/input/tsc2007.h b/nuttx/drivers/input/tsc2007.h deleted file mode 100644 index 76d5962bf..000000000 --- a/nuttx/drivers/input/tsc2007.h +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************************** - * drivers/input/tsc2007.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "1.2V to 3.6V, 12-Bit, Nanopower, 4-Wire Micro TOUCH SCREEN CONTROLLER - * with I2C Interface," SBAS405A March 2007, Revised, March 2009, Texas - * Instruments Incorporated - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ********************************************************************************************/ - -/* The TSC2007 is an analog interface circuit for a human interface touch screen device. - * All peripheral functions are controlled through the command byte and onboard state - * machines. - */ - -#ifndef __DRIVERS_INPUT_TSC2007_H -#define __DRIVERS_INPUT_TSC2007_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ - -/* TSC2007 Address */ - -#define TSC2007_ADDRESS_MASK (0xf8) /* Bits 3-7: Invariant part of TSC2007 address */ -#define TSC2007_ADDRESS (0x90) /* Bits 3-7: Always set at '10010' */ -#define TSC2007_A1 (1 << 2) /* Bit 2: A1 */ -#define TSC2007_A0 (1 << 1) /* Bit 1: A1 */ -#define TSC2007_READ (1 << 0) /* Bit0=1: Selects read operation */ -#define TSC2007_WRITE (0) /* Bit0=0: Selects write operation */ - -/* TSC2007 Command Byte */ - -#define TSC2007_CMD_FUNC_SHIFT (4) /* Bits 4-7: Converter function select bits */ -#define TSC2007_CMD_FUNC_MASK (15 << TSC2007_CMD_FUNC_SHIFT) -# define TSC2007_CMD_FUNC_TEMP0 (0 << TSC2007_CMD_FUNC_SHIFT) /* Measure TEMP0 */ -# define TSC2007_CMD_FUNC_AUX (2 << TSC2007_CMD_FUNC_SHIFT) /* Measure AUX */ -# define TSC2007_CMD_FUNC_TEMP1 (4 << TSC2007_CMD_FUNC_SHIFT) /* Measure TEMP1 */ -# define TSC2007_CMD_FUNC_XON (8 << TSC2007_CMD_FUNC_SHIFT) /* Activate X-drivers */ -# define TSC2007_CMD_FUNC_YON (9 << TSC2007_CMD_FUNC_SHIFT) /* Activate Y-drivers */ -# define TSC2007_CMD_FUNC_YXON (10 << TSC2007_CMD_FUNC_SHIFT) /* Activate Y+, X-drivers */ -# define TSC2007_CMD_FUNC_SETUP (11 << TSC2007_CMD_FUNC_SHIFT) /* Setup command */ -# define TSC2007_CMD_FUNC_XPOS (12 << TSC2007_CMD_FUNC_SHIFT) /* Measure X position */ -# define TSC2007_CMD_FUNC_YPOS (13 << TSC2007_CMD_FUNC_SHIFT) /* Measure Y position */ -# define TSC2007_CMD_FUNC_Z1POS (14 << TSC2007_CMD_FUNC_SHIFT) /* Measure Z1 position */ -# define TSC2007_CMD_FUNC_Z2POS (15 << TSC2007_CMD_FUNC_SHIFT) /* Measure Z2 positionn */ -#define TSC2007_CMD_PWRDN_SHIFT (2) /* Bits 2-3: Power-down bits */ -#define TSC2007_CMD_PWRDN_MASK (3 << TSC2007_CMD_PWRDN_SHIFT) -# define TSC2007_CMD_PWRDN_IRQEN (0 << TSC2007_CMD_PWRDN_SHIFT) /* 00: Power down between cycles; PENIRQ enabled */ -# define TSC2007_CMD_ADCON_IRQDIS (1 << TSC2007_CMD_PWRDN_SHIFT) /* 01: A/D converter on; PENIRQ disabled */ -# define TSC2007_CMD_ADCOFF_IRQEN (2 << TSC2007_CMD_PWRDN_SHIFT) /* 10: A/D converter off; PENIRQ enabled. */ - /* 11: A/D converter on; PENIRQ disabled. */ -#define TSC2007_CMD_12BIT (0) /* Bit 1: 0=12-bit */ -#define TSC2007_CMD_8BIT (1 << 1) /* Bit 1: 1=8-bit */ - /* Bit 0: Don't care */ - -/* TSC2007 Setup Command */ - -#define TSC2007_SETUP_CMD TSC2007_CMD_FUNC_SETUP /* Bits 4-7: Setup command */ - /* Bits 2-3: Must be zero */ -#define TSC2007_CMD_USEMAV (0) /* Bit 1: 0: Use the onboard MAV filter (default) */ -#define TSC2007_CMD_BYPASSMAV (1 << 1) /* Bit 1: 1: Bypass the onboard MAV filter */ -#define TSC2007_CMD_PU_50KOHM (0) /* Bit 0: 0: RIRQ = 50kOhm (default). */ -#define TSC2007_CMD_PU_90KOHM (1 << 1) /* Bit 0: 1: 1: RIRQ = 90kOhm */ - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_INPUT_TSC2007_H */ diff --git a/nuttx/drivers/lcd/Kconfig b/nuttx/drivers/lcd/Kconfig deleted file mode 100644 index 2d20003ac..000000000 --- a/nuttx/drivers/lcd/Kconfig +++ /dev/null @@ -1,330 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config LCD_NOGETRUN - bool "Write-only LCD" - default n - ---help--- - Many LCD hardware interfaces provide only minimal graphics capability. In - particulary, many simple LCD interfaces are write only. That is we, can - write graphics data to the LCD device memory, but we cannot read it back. - If the LCD hardware does not support reading the graphics memory, then - this option should be defined so that the NX layer can taking alternative - measures when the LCD is not readable. For example, if the LCD is not - readable, then NX will not attempt to support transparency. - - See also NX_WRITEONLY in the graphics support menu. - -config LCD_MAXCONTRAST - int "LCD maximum contrast" - default 63 if NOKIA6100_S1D15G10 - default 127 if NOKIA6100_PCF8833 - default 255 if LCD_P14201 - default 63 - ---help--- - must be 63 with the Epson controller and 127 with - the Phillips controller. - -config LCD_MAXPOWER - int "LCD maximum power" - default 1 - ---help--- - Maximum value of backlight setting. The backlight - control is managed outside of the 6100 driver so this value has no - meaning to the driver. Board-specific logic may place restrictions on - this value. - -config LCD_P14201 - bool "Rit P1402 series display" - default n - ---help--- - p14201.c. Driver for RiT P14201 series display with SD1329 IC - controller. This OLED is used with older versions of the - TI/Luminary LM3S8962 Evaluation Kit. - -if LCD_P14201 -config P14201_NINTERFACES - int "Number of physical P14201 devices" - default 1 - range 1,1 - ---help--- - Specifies the number of physical P14201 - devices that will be supported. - -config P14201_SPIMODE - int "SPI mode" - default 2 - range 0,3 - ---help--- - Controls the SPI mode - -config P14201_FREQUENCY - int "SPI frequency" - default 1000000 - ---help--- - Define to use a different bus frequency,FIXME DEFAULT VALUE OK? - -config P14201_FRAMEBUFFER - bool "Enable P14201 GDDRAM cache" - default y - ---help--- - If defined, accesses will be performed - using an in-memory copy of the OLEDs GDDRAM. This cost of this - buffer is 128 * 96 / 2 = 6Kb. If this is defined, then the driver - will be fully functional. If not, then it will have the following - limitations: - - Reading graphics memory cannot be supported, and - - All pixel writes must be aligned to byte boundaries. - The latter limitation effectively reduces the 128x96 disply to 64x96. -endif - -config LCD_NOKIA6100 - bool "Nokia 6100 display support" - default n - ---help--- - nokia6100.c. Supports the Nokia 6100 display with either the Philips - PCF883 or the Epson S1D15G10 display controller. This LCD is used - with the Olimex LPC1766-STK (but has not been fully integrated). -if LCD_NOKIA6100 -config NOKIA6100_NINTERFACES - int "Number of physical NOKIA6100 devices" - default 1 - range 1,1 - ---help--- - Specifies the number of physical Nokia - 6100 devices that will be supported. - -choice NOKIA6100_CONTROLLER - prompt "Controller Setup" - default NOKIA6100_S1D15G10 -config NOKIA6100_S1D15G10 - bool "S1D15G10 controller" - ---help--- - Selects the Epson S1D15G10 display controller - -config NOKIA6100_PCF8833 - bool "PCF8833 controller" - ---help--- - Selects the Phillips PCF8833 display controller -endchoice - -config NOKIA6100_SPIMODE - int "SPI mode" - default 0 - range 0,3 - ---help--- - Controls the SPI mode - -config NOKIA6100_FREQUENCY - int "SPI frequency" - default 1000000 - ---help--- - Define to use a different bus frequency - -config NOKIA6100_BLINIT - bool "Back light initial" - default n - ---help--- - Initial backlight setting - The following may need to be tuned for your hardware: - -config NOKIA6100_BPP - int "Display bits per pixel" - default 8 - ---help--- - Device supports 8, 12, and 16 bits per pixel. - -config NOKIA6100_INVERT - int "Display inversion" - default 1 - range 0,1 - ---help--- - Display inversion, 0 or 1, Default: 1 - -config NOKIA6100_MY - int "Display row direction" - default 0 - range 0,1 - ---help--- - Display row direction, 0 or 1, Default: 0 - -config NOKIA6100_MX - int "Display column direction" - default 1 - range 0,1 - ---help--- - Display column direction, 0 or 1, Default: 1 - -config NOKIA6100_V - int "Display address direction" - default 0 - range 0,1 - ---help--- - Display address direction, 0 or 1, Default: 0 - -config NOKIA6100_ML - int "Display scan direction" - default 0 - range 0,1 - ---help--- - Display scan direction, 0 or 1, Default: 0 - -config NOKIA6100_RGBORD - int "Display RGB order" - default 0 - range 0,1 - ---help--- - Display RGB order, 0 or 1, Default: 0 - Required LCD driver settings: -endif - -config LCD_UG9664HSWAG01 - bool "UG-9664HSWAG01 OLED Display Module" - default n - ---help--- - OLED Display Module, UG-9664HSWAG01, Univision Technology Inc. Used - with the LPCXpresso and Embedded Artists base board. - - Required LCD driver settings: - LCD_MAXCONTRAST should be 255, but any value >0 and <=255 will be accepted. - LCD_MAXPOWER should be 1: 0=off, 1=on - - Required SPI driver settings: - SPI_CMDDATA - Include support for cmd/data selection. - -if LCD_UG9664HSWAG01 - -config UG9664HSWAG01_SPIMODE - int "UG-9664HSWAG01 SPI Mode" - default 0 - ---help--- - Controls the SPI mode - -config UG9664HSWAG01_FREQUENCY - int "UG-9664HSWAG01 SPI Frequency" - default 3500000 - ---help--- - Define to use a different bus frequency - -config UG9664HSWAG01_NINTERFACES - int "Number of UG-9664HSWAG01 Devices" - default 1 - ---help--- - Specifies the number of physical UG-9664HSWAG01 devices that will be - supported. NOTE: At present, this must be undefined or defined to be 1. - -config UG9664HSWAG01_POWER - bool "Power control" - default n - ---help--- - If the hardware supports a controllable OLED a power supply, this - configuration should be defined. In this case the system must - provide an interface ug_power(). - -endif - -config LCD_UG2864AMBAG01 - bool "UG-2864AMBAG01 OLED Display Module" - default n - ---help--- - OLED Display Module, UG-2864AMBAG01, Univision Technology Inc. - - Required LCD driver settings: - LCD_MAXCONTRAST should be 255, but any value >0 and <=255 will be accepted. - LCD_MAXPOWER should be 1: 0=off, 1=on - - Required SPI driver settings: - SPI_CMDDATA - Include support for cmd/data selection. - -if LCD_UG2864AMBAG01 - - config UG2864AMBAG01_SPIMODE - int "UG-2864AMBAG01 SPI Mode" - default 3 - ---help--- - Controls the SPI mode - -config UG2864AMBAG01_FREQUENCY - int "UG-2864AMBAG01 SPI Frequency" - default 3500000 - ---help--- - Define to use a different bus frequency - -config UG2864AMBAG01_NINTERFACES - int "Number of UG-2864AMBAG01 Devices" - default 1 - ---help--- - Specifies the number of physical UG-9664HSWAG01 devices that will be - supported. NOTE: At present, this must be undefined or defined to be 1. - -endif - -config LCD_SSD1289 - bool "LCD Based on SSD1289 Controller" - default n - ---help--- - Enables generic support for any LCD based on the Solomon Systech, - Ltd, SSD1289 Controller. Use of this driver will usually require so - detailed customization of the LCD initialization code as necessary - for the specific LCD driven by the SSD1289 controller. - -if LCD_SSD1289 - -choice - prompt "SSD1289 Initialization Profile" - default SSD1289_PROFILE1 - -config SSD1289_PROFILE1 - bool "Profile 1" - -config SSD1289_PROFILE2 - bool "Profile 2" - -config SSD1289_PROFILE3 - bool "Profile 3" - -endchoice -endif - -choice - prompt "LCD Orientation" - default LCD_LANDSCAPE - depends on LCD - ---help--- - Some LCD drivers may support displays in different orientations. - If the LCD driver supports this capability, than these are configuration - options to select that display orientation. - -config LCD_LANDSCAPE - bool "Landscape orientation" - ---help--- - Define for "landscape" orientation support. Landscape mode refers one - of two orientations where the the display is wider than it is tall - (LCD_RLANDSCAPE is the other). This is the default orientation. - -config LCD_PORTRAIT - bool "Portrait orientation" - ---help--- - Define for "portrait" orientation support. Portrait mode refers one - of two orientations where the the display is taller than it is wide - (LCD_RPORTAIT is the other). - -config LCD_RPORTRAIT - bool "Reverse portrait display" - ---help--- - Define for "reverse portrait" orientation support. Reverse portrait mode - refers one of two orientations where the the display is taller than it is - wide (LCD_PORTAIT is the other). - -config LCD_RLANDSCAPE - bool "Reverse landscape orientation" - ---help--- - Define for "reverse landscape" orientation support. Reverse landscape mode - refers one of two orientations where the the display is wider than it is - tall (LCD_LANDSCAPE is the other). - -endchoice diff --git a/nuttx/drivers/lcd/Make.defs b/nuttx/drivers/lcd/Make.defs deleted file mode 100644 index 067f76f4e..000000000 --- a/nuttx/drivers/lcd/Make.defs +++ /dev/null @@ -1,76 +0,0 @@ -############################################################################ -# drivers/lcd/Make.defs -# -# Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Don't build anything if there is no NX support for LCD drivers - -ifeq ($(CONFIG_NX_LCDDRIVER),y) - -# Include LCD drivers - -ifeq ($(CONFIG_LCD_P14201),y) - CSRCS += p14201.c -endif - -ifeq ($(CONFIG_LCD_NOKIA6100),y) - CSRCS += nokia6100.c -endif - -ifeq ($(CONFIG_LCD_UG2864AMBAG01),y) - CSRCS += ug-2864ambag01.c -endif - -ifeq ($(CONFIG_LCD_UG2864HSWEG01),y) - CSRCS += ug-2864hsweg01.c -endif - -ifeq ($(CONFIG_LCD_UG9664HSWAG01),y) - CSRCS += ug-9664hswag01.c -endif - -ifeq ($(CONFIG_LCD_SSD1289),y) - CSRCS += ssd1289.c -endif - -ifeq ($(CONFIG_LCD_MIO283QT2),y) - CSRCS += mio283qt2.c -endif - -# Include LCD driver build support - -DEPPATH += --dep-path lcd -VPATH += :lcd -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)lcd} -endif - diff --git a/nuttx/drivers/lcd/README.txt b/nuttx/drivers/lcd/README.txt deleted file mode 100644 index 0472043e6..000000000 --- a/nuttx/drivers/lcd/README.txt +++ /dev/null @@ -1,189 +0,0 @@ -nuttx/drivers/lcd README -======================== - -This is the README.txt file for the drivers/lcd/ directory. - -Contents -======== - - - LCD Header files - include/nuttx/lcd/lcd.h - struct lcd_dev_s - - Binding LCD Drivers - - Examples: /drivers/lcd/ - - Examples: configs/ - - graphics/ - -LCD Header files -================ - - include/nuttx/lcd/lcd.h - - Structures and APIs needed to work with LCD drivers are provided in - this header file. This header file also depends on some of the same - definitions used for the frame buffer driver as privided in - include/nuttx/fb.h. - - struct lcd_dev_s - - Each LCD device driver must implement an instance of struct lcd_dev_s. - That structure defines a call table with the following methods: - - - Get information about the LCD video controller configuration and the - configuration of each LCD color plane. - - int (*getvideoinfo)(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); - int (*getplaneinfo)(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - - - The following are provided only if the video hardware supports RGB - color mapping: - - int (*getcmap)(FAR struct lcd_dev_s *dev, - FAR struct fb_cmap_s *cmap); - int (*putcmap)(FAR struct lcd_dev_s *dev, - FAR const struct fb_cmap_s *cmap); - - - The following are provided only if the video hardware supports a - hardware cursor: - - int (*getcursor)(FAR struct lcd_dev_s *dev, - FAR struct fb_cursorattrib_s *attrib); - int (*setcursor)(FAR struct lcd_dev_s *dev, - FAR struct fb_setcursor_s *settings); - - - Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: - full on). On backlit LCDs, this setting may correspond to the - backlight setting. - - int (*getpower)(struct lcd_dev_s *dev); - - - Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: - full on). On backlit LCDs, this setting may correspond to the - backlight setting. - - int (*setpower)(struct lcd_dev_s *dev, int power); - - - Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST) */ - - int (*getcontrast)(struct lcd_dev_s *dev); - - - Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST) - - int (*setcontrast)(struct lcd_dev_s *dev, unsigned int contrast); - -Binding LCD Drivers -=================== - - LCD drivers are not normally directly accessed by user code, but are - usually bound to another, higher level device driver. In general, the - binding sequence is: - - 1. Get an instance of struct lcd_dev_s from the hardware-specific LCD - device driver, and - 2. Provide that instance to the initialization method of the higher - level device driver. - -Examples: /drivers/lcd/ -======================= - -Re-usable LCD drivers reside in the drivers/lcd directory: - - mio283qt2.c. This is a driver for the MI0283QT-2 LCD from Multi-Inno - Technology Co., Ltd. This LCD is based on the Himax HX8347-D LCD - controller. - - nokia6100.c. Supports the Nokia 6100 display with either the Philips - PCF883 or the Epson S1D15G10 display controller. This LCD is used - with the Olimex LPC1766-STK (but has not been fully integrated). - - p14201.c. Driver for RiT P14201 series display with SD1329 IC - controller. This OLED is used with older versions of the - TI/Luminary LM3S8962 Evaluation Kit. - - ssd12989.c. Generic LCD driver for LCDs based on the Solomon Systech - SSD1289 LCD controller. Think of this as a template for an LCD driver - that you will proably ahve to customize for any particular LCD - hardware. (see also configs/hymini-stm32v/src/ssd1289.c below). - - ug-9664hswag01.c. OLED Display Module, UG-9664HSWAG01", Univision - Technology Inc. Used with the LPC Xpresso and Embedded Artists - base board. - -Examples: configs/ -================== - -There are additional LCD drivers in the configs//src directory -that support additional LCDs. LCD drivers in the configuration directory -if they support some differ LCD interface (such as a parallel interface) -that makes then less re-usable: - - SSD1783 Drivers: - - configs/compal_e99/src/ssd1783.c - - SSD1289 Drivers: - - configs/hymini-stm32v/src/ssd1289.c. See also drivers/lcd/ssd1298.c - above. - configs/stm32f4discovery/src/up_ssd1289.c. This examples is the - bottom half for the SSD1289 driver at drivers/lcd/ssd1289.c - configs/hymini-stm32v/src/ssd1289.c. See also drivers/lcd/ssd1298.c - above. - configs/shenzhou/src/up_ssd1289.c - - kwikstik-k40: - - configs/kwikstik-k40/src/up_lcd.c. Don't waste your time. This is - just a stub. - - Nokia LCD Drivers: - - configs/olimex-lpc1766stk/src/up_lcd.c. This examples is the - bottom half for the driver at drivers/lcd/nokia6100.c. - This was never completedly debugged ... there are probably issues - with that nasty 9-bit SPI interfaces. - - HX8346: - - configs/sam3u-ek/src/up_lcd.c. The SAM3U-EK developement board features - a TFT/Transmissive color LCD module with touch-screen, FTM280C12D, - with integrated driver IC HX8346. - - HX8347: - - configs/pic32mx7mmb/src/up_mio283qt2.c. This driver is for the MI0283QT-2 - LCD from Multi-Inno Technology Co., Ltd. This LCD is based on the Himax - HX8347-D LCD controller. - - ILI93xx and Similar: - - configs/stm3210e-eval/src/up_lcd.c. This driver supports the following - LCDs: - - 1. Ampire AM-240320LTNQW00H - 2. Orise Tech SPFD5408B - 3. RenesasSP R61580 - - configs/stm3220g-eval/src/up_lcd.c and configs/stm3240g-eval/src/up_lcd.c. - AM-240320L8TNQW00H (LCD_ILI9320 or LCD_ILI9321) and - AM-240320D5TOQW01H (LCD_ILI9325) - configs/shenzhou/src/up_ili93xx.c. Another ILI93xx driver. - - OLEDs: - - configs/stm32f4discovery/src/up_ug2864ambag01.c - configs/stm32f4discovery/src/up_ug2864hsweg01.c - configs/zp214xpa/src/up_ug2864ambag01.c - - Alphnumeric LCD Displays: - - configs/skp16c26/src/up_lcd.c. Untested alphanumeric LCD driver. - configs/pcblogic-pic32/src/up_lcd1602.c - -graphics/ -========= - - See also the usage of the LCD driver in the graphics/ directory. - diff --git a/nuttx/drivers/lcd/mio283qt2.c b/nuttx/drivers/lcd/mio283qt2.c deleted file mode 100644 index 4c8835eef..000000000 --- a/nuttx/drivers/lcd/mio283qt2.c +++ /dev/null @@ -1,1014 +0,0 @@ -/************************************************************************************** - * drivers/lcd/mio283qt2.c - * - * This is a driver for the MI0283QT-2 LCD from Multi-Inno Technology Co., Ltd. This - * LCD is based on the Himax HX8347-D LCD controller. - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * - * References: - * 1) LCD Module Specification, Model : MI0283QT-2, Multi-Inno Technology Co., - * Ltd., Revision 1.0 - * 2) Data Sheet: HX8347-D(T), 240RGB x 320 dot, 262K color, with internal GRAM, TFT - * Mobile Single Chip Driver Version 02 March, Doc No. HX8347-D(T)-DS, Himax - * Technologies, Inc., 2009, - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_LCD_MIO283QT2 - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ -/* Configuration **********************************************************************/ - -/* Check contrast selection */ - -#if !defined(CONFIG_LCD_MAXCONTRAST) -# define CONFIG_LCD_MAXCONTRAST 1 -#endif - -/* Check power setting */ - -#if !defined(CONFIG_LCD_MAXPOWER) || CONFIG_LCD_MAXPOWER < 1 -# define CONFIG_LCD_MAXPOWER 1 -#endif - -#if CONFIG_LCD_MAXPOWER > 255 -# error "CONFIG_LCD_MAXPOWER must be less than 256 to fit in uint8_t" -#endif - -/* Check orientation */ - -#if defined(CONFIG_LCD_PORTRAIT) -# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) || defined(CONFIG_LCD_RPORTRAIT) -# error "Cannot define both portrait and any other orientations" -# endif -#elif defined(CONFIG_LCD_RPORTRAIT) -# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -# error "Cannot define both rportrait and any other orientations" -# endif -#elif defined(CONFIG_LCD_LANDSCAPE) -# ifdef CONFIG_LCD_RLANDSCAPE -# error "Cannot define both landscape and any other orientations" -# endif -#elif !defined(CONFIG_LCD_RLANDSCAPE) -# define CONFIG_LCD_LANDSCAPE 1 -#endif - -/* Define CONFIG_DEBUG_LCD to enable detailed LCD debug output. Verbose debug must - * also be enabled. - */ - -#ifndef CONFIG_DEBUG -# undef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_GRAPHICS -# undef CONFIG_DEBUG_LCD -#endif - -#ifndef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_LCD -#endif - -/* Display/Color Properties ***********************************************************/ -/* Display Resolution */ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -# define MIO283QT2_XRES 320 -# define MIO283QT2_YRES 240 -#else -# define MIO283QT2_XRES 240 -# define MIO283QT2_YRES 320 -#endif - -/* Color depth and format */ - -#define MIO283QT2_BPP 16 -#define MIO283QT2_COLORFMT FB_FMT_RGB16_565 - -/* Hardware LCD/LCD controller definitions ********************************************/ -/* In this driver, I chose to use all literal constants for register address and - * values. Some recent experiences have shown me that during LCD bringup, it is more - * important to know the binary values rather than nice, people friendly names. Sad, - * but true. - */ - -#define HIMAX_ID 0x0047 - -/* LCD Profiles ***********************************************************************/ -/* Many details of the controller initialization must, unfortunately, vary from LCD to - * LCD. I have looked at the spec and at three different drivers for LCDs that have - * MIO283QT2 controllers. I have tried to summarize these differences as "LCD profiles" - * - * Most of the differences between LCDs are nothing more than a few minor bit - * settings. The most significant difference betwen LCD drivers in is the - * manner in which the LCD is powered up and in how the power controls are set. - * My suggestion is that if you have working LCD initialization code, you should - * simply replace the code in mio283qt2_hwinitialize with your working code. - */ - -#if defined (CONFIG_MIO283QT2_PROFILE2) -# undef MIO283QT2_USE_SIMPLE_INIT - - /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */ - -# define PWRCTRL1_SETTING \ - (MIO283QT2_PWRCTRL1_AP_SMMED | MIO283QT2_PWRCTRL1_DC_FLINEx24 | \ - MIO283QT2_PWRCTRL1_BT_p5m4 | MIO283QT2_PWRCTRL1_DCT_FLINEx24) - - /* PWRCTRL2: 5.1v */ - -# define PWRCTRL2_SETTING MIO283QT2_PWRCTRL2_VRC_5p1V - - /* PWRCTRL3: x 2.165 - * NOTE: Many drivers have bit 8 set which is not defined in the MIO283QT2 spec. - */ - -# define PWRCTRL3_SETTING MIO283QT2_PWRCTRL3_VRH_x2p165 - - /* PWRCTRL4: VDV=9 + VCOMG */ - -# define PWRCTRL4_SETTING (MIO283QT2_PWRCTRL4_VDV(9) | MIO283QT2_PWRCTRL4_VCOMG) - - /* PWRCTRL5: VCM=56 + NOTP */ - -# define PWRCTRL5_SETTING (MIO283QT2_PWRCTRL5_VCM(56) | MIO283QT2_PWRCTRL5_NOTP) - -#elif defined (CONFIG_MIO283QT2_PROFILE3) -# undef MIO283QT2_USE_SIMPLE_INIT - - /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */ - -# define PWRCTRL1_SETTING \ - (MIO283QT2_PWRCTRL1_AP_SMMED | MIO283QT2_PWRCTRL1_DC_FLINEx24 | \ - MIO283QT2_PWRCTRL1_BT_p5m4 | MIO283QT2_PWRCTRL1_DCT_FLINEx24) - - /* PWRCTRL2: 5.1v */ - -# define PWRCTRL2_SETTING MIO283QT2_PWRCTRL2_VRC_5p1V - - /* PWRCTRL3: x 2.165 - * NOTE: Many drivers have bit 8 set which is not defined in the MIO283QT2 spec. - */ - -# define PWRCTRL3_SETTING MIO283QT2_PWRCTRL3_VRH_x2p165 - - /* PWRCTRL4: VDV=9 + VCOMG */ - -# define PWRCTRL4_SETTING (MIO283QT2_PWRCTRL4_VDV(9) | MIO283QT2_PWRCTRL4_VCOMG) - - /* PWRCTRL5: VCM=56 + NOTP */ - -# define PWRCTRL5_SETTING (MIO283QT2_PWRCTRL5_VCM(56) | MIO283QT2_PWRCTRL5_NOTP) - -#else /* if defined (CONFIG_MIO283QT2_PROFILE1) */ -# undef MIO283QT2_USE_SIMPLE_INIT -# define MIO283QT2_USE_SIMPLE_INIT 1 - - /* PWRCTRL1: AP=medium-to-large, DC=Fosc/4, BT=+5/-4, DCT=Fosc/4 */ - -# define PWRCTRL1_SETTING \ - (MIO283QT2_PWRCTRL1_AP_MEDLG | MIO283QT2_PWRCTRL1_DC_FOSd4 | \ - MIO283QT2_PWRCTRL1_BT_p5m4 | MIO283QT2_PWRCTRL1_DCT_FOSd4) - - /* PWRCTRL2: 5.3v */ - -# define PWRCTRL2_SETTING MIO283QT2_PWRCTRL2_VRC_5p3V - - /* PWRCTRL3: x 2.570 - * NOTE: Many drivers have bit 8 set which is not defined in the MIO283QT2 spec. - */ - -# define PWRCTRL3_SETTING MIO283QT2_PWRCTRL3_VRH_x2p570 - - /* PWRCTRL4: VDV=12 + VCOMG */ - -# define PWRCTRL4_SETTING (MIO283QT2_PWRCTRL4_VDV(12) | MIO283QT2_PWRCTRL4_VCOMG) - - /* PWRCTRL5: VCM=60 + NOTP */ - -# define PWRCTRL5_SETTING (MIO283QT2_PWRCTRL5_VCM(60) | MIO283QT2_PWRCTRL5_NOTP) - -#endif - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_DEBUG_LCD -# define lcddbg dbg -# define lcdvdbg vdbg -#else -# define lcddbg(x...) -# define lcdvdbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct mio283qt2_dev_s -{ - /* Publically visible device structure */ - - struct lcd_dev_s dev; - - /* Private LCD-specific information follows */ - - FAR struct mio283qt2_lcd_s *lcd; /* The contained platform-specific, LCD interface */ - uint8_t power; /* Current power setting */ - - /* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - - uint16_t runbuffer[MIO283QT2_XRES]; -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ -/* Low Level LCD access */ - -static void mio283qt2_putreg(FAR struct mio283qt2_lcd_s *lcd, uint8_t regaddr, - uint16_t regval); -#ifndef CONFIG_LCD_NOGETRUN -static uint16_t mio283qt2_readreg(FAR struct mio283qt2_lcd_s *lcd, uint8_t regaddr); -#endif -static inline void mio283qt2_gramwrite(FAR struct mio283qt2_lcd_s *lcd, - uint16_t rgbcolor); -#ifndef CONFIG_LCD_NOGETRUN -static inline void mio283qt2_readsetup(FAR struct mio283qt2_lcd_s *lcd, - FAR uint16_t *accum); -static inline uint16_t mio283qt2_gramread(FAR struct mio283qt2_lcd_s *lcd, - FAR uint16_t *accum); -#endif -static void mio283qt2_setarea(FAR struct mio283qt2_lcd_s *lcd, - uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); - -/* LCD Data Transfer Methods */ - -static int mio283qt2_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels); -static int mio283qt2_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int mio283qt2_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int mio283qt2_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int mio283qt2_getpower(FAR struct lcd_dev_s *dev); -static int mio283qt2_setpower(FAR struct lcd_dev_s *dev, int power); -static int mio283qt2_getcontrast(FAR struct lcd_dev_s *dev); -static int mio283qt2_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast); - -/* Initialization */ - -static inline int mio283qt2_hwinitialize(FAR struct mio283qt2_dev_s *priv); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This driver can support only a signal MIO283QT2 device. This is due to an - * unfortunate decision made whent he getrun and putrun methods were designed. The - * following is the single MIO283QT2 driver state instance: - */ - -static struct mio283qt2_dev_s g_lcddev; - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: mio283qt2_putreg(lcd, - * - * Description: - * Write to an LCD register - * - **************************************************************************************/ - -static void mio283qt2_putreg(FAR struct mio283qt2_lcd_s *lcd, - uint8_t regaddr, uint16_t regval) -{ - /* Set the index register to the register address and write the register contents */ - - lcd->index(lcd, regaddr); - lcd->write(lcd, regval); -} - -/************************************************************************************** - * Name: mio283qt2_readreg - * - * Description: - * Read from an LCD register - * - **************************************************************************************/ - -#ifndef CONFIG_LCD_NOGETRUN -static uint16_t mio283qt2_readreg(FAR struct mio283qt2_lcd_s *lcd, uint8_t regaddr) -{ - /* Set the index register to the register address and read the register contents. */ - - lcd->index(lcd, regaddr); - return lcd->read(lcd); -} -#endif - -/************************************************************************************** - * Name: mio283qt2_gramselect - * - * Description: - * Setup to read or write multiple pixels to the GRAM memory - * - **************************************************************************************/ - -static inline void mio283qt2_gramselect(FAR struct mio283qt2_lcd_s *lcd) -{ - lcd->index(lcd, 0x22); -} - -/************************************************************************************** - * Name: mio283qt2_gramwrite - * - * Description: - * Setup to read or write multiple pixels to the GRAM memory - * - **************************************************************************************/ - -static inline void mio283qt2_gramwrite(FAR struct mio283qt2_lcd_s *lcd, uint16_t data) -{ - lcd->write(lcd, data); -} - -/************************************************************************************** - * Name: mio283qt2_readsetup - * - * Description: - * Prime the operation by reading one pixel from the GRAM memory if necessary for - * this LCD type. When reading 16-bit gram data, there may be some shifts in the - * returned data: - * - * - ILI932x: Discard first dummy read; no shift in the return data - * - **************************************************************************************/ - -#ifndef CONFIG_LCD_NOGETRUN -static inline void mio283qt2_readsetup(FAR struct mio283qt2_lcd_s *lcd, - FAR uint16_t *accum) -{ -#if 0 /* Probably not necessary... untested */ - /* Read-ahead one pixel */ - - *accum = lcd->read(lcd); -#endif -} -#endif - -/************************************************************************************** - * Name: mio283qt2_gramread - * - * Description: - * Read one correctly aligned pixel from the GRAM memory. Possibly shifting the - * data and possibly swapping red and green components. - * - * - ILI932x: Unknown -- assuming colors are in the color order - * - **************************************************************************************/ - -#ifndef CONFIG_LCD_NOGETRUN -static inline uint16_t mio283qt2_gramread(FAR struct mio283qt2_lcd_s *lcd, - FAR uint16_t *accum) -{ - /* Read the value (GRAM register already selected) */ - - return lcd->read(lcd); -} -#endif - -/************************************************************************************** - * Name: mio283qt2_setarea - * - * Description: - * Set the cursor position. In landscape mode, the "column" is actually the physical - * Y position and the "row" is the physical X position. - * - **************************************************************************************/ - -static void mio283qt2_setarea(FAR struct mio283qt2_lcd_s *lcd, - uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) -{ - mio283qt2_putreg(lcd, 0x03, (x0 & 0x00ff)); /* set x0 */ - mio283qt2_putreg(lcd, 0x02, (x0 >> 8)); /* set x0 */ - mio283qt2_putreg(lcd, 0x05, (x1 & 0x00ff)); /* set x1 */ - mio283qt2_putreg(lcd, 0x04, (x1 >> 8)); /* set x1 */ - mio283qt2_putreg(lcd, 0x07, (y0 & 0x00ff)); /* set y0 */ - mio283qt2_putreg(lcd, 0x06, (y0 >> 8)); /* set y0 */ - mio283qt2_putreg(lcd, 0x09, (y1 & 0x00ff)); /* set y1 */ - mio283qt2_putreg(lcd, 0x08, (y1 >> 8)); /* set y1 */ -} - -/************************************************************************************** - * Name: mio283qt2_dumprun - * - * Description: - * Dump the contexts of the run buffer: - * - * run - The buffer in containing the run read to be dumped - * npixels - The number of pixels to dump - * - **************************************************************************************/ - -#if 0 /* Sometimes useful */ -static void mio283qt2_dumprun(FAR const char *msg, FAR uint16_t *run, size_t npixels) -{ - int i, j; - - syslog("\n%s:\n", msg); - for (i = 0; i < npixels; i += 16) - { - up_putc(' '); - syslog(" "); - for (j = 0; j < 16; j++) - { - syslog(" %04x", *run++); - } - up_putc('\n'); - } -} -#endif - -/************************************************************************************** - * Name: mio283qt2_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD: - * - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int mio283qt2_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - FAR struct mio283qt2_dev_s *priv = &g_lcddev; - FAR struct mio283qt2_lcd_s *lcd = priv->lcd; - FAR const uint16_t *src = (FAR const uint16_t*)buffer; - int i; - - /* Buffer must be provided and aligned to a 16-bit address boundary */ - - lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); - - /* Select the LCD */ - - lcd->select(lcd); - - /* Write the run to GRAM. */ - - mio283qt2_setarea(lcd, col, row, col + npixels - 1, row); - mio283qt2_gramselect(lcd); - - for (i = 0; i < npixels; i++) - { - mio283qt2_gramwrite(lcd, *src); - src++; - } - - /* De-select the LCD */ - - lcd->deselect(lcd); - return OK; -} - -/************************************************************************************** - * Name: mio283qt2_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int mio283qt2_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ -#ifndef CONFIG_LCD_NOGETRUN - FAR struct mio283qt2_dev_s *priv = &g_lcddev; - FAR struct mio283qt2_lcd_s *lcd = priv->lcd; - FAR uint16_t *dest = (FAR uint16_t*)buffer; - uint16_t accum; - int i; - - /* Buffer must be provided and aligned to a 16-bit address boundary */ - - lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); - - /* Select the LCD */ - - lcd->select(lcd); - - /* Read the run from GRAM. */ - - /* Select the LCD */ - - lcd->select(lcd); - - /* Red the run fram GRAM. */ - - mio283qt2_setarea(lcd, col, row, col + npixels - 1, row); - mio283qt2_gramselect(lcd); - - /* Prime the pump for unaligned read data */ - - mio283qt2_readsetup(lcd, &accum); - - for (i = 0; i < npixels; i++) - { - *dest++ = mio283qt2_gramread(lcd, &accum); - } - - /* De-select the LCD */ - - lcd->deselect(lcd); - return OK; -#else - return -ENOSYS; -#endif -} - -/************************************************************************************** - * Name: mio283qt2_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int mio283qt2_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - lcdvdbg("fmt: %d xres: %d yres: %d nplanes: 1\n", - MIO283QT2_COLORFMT, MIO283QT2_XRES, MIO283QT2_XRES); - - vinfo->fmt = MIO283QT2_COLORFMT; /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - vinfo->xres = MIO283QT2_XRES; /* Horizontal resolution in pixel columns */ - vinfo->yres = MIO283QT2_YRES; /* Vertical resolution in pixel rows */ - vinfo->nplanes = 1; /* Number of color planes supported */ - return OK; -} - -/************************************************************************************** - * Name: mio283qt2_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int mio283qt2_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - FAR struct mio283qt2_dev_s *priv = (FAR struct mio283qt2_dev_s *)dev; - - DEBUGASSERT(dev && pinfo && planeno == 0); - lcdvdbg("planeno: %d bpp: %d\n", planeno, MIO283QT2_BPP); - - pinfo->putrun = mio283qt2_putrun; /* Put a run into LCD memory */ - pinfo->getrun = mio283qt2_getrun; /* Get a run from LCD memory */ - pinfo->buffer = (uint8_t*)priv->runbuffer; /* Run scratch buffer */ - pinfo->bpp = MIO283QT2_BPP; /* Bits-per-pixel */ - return OK; -} - -/************************************************************************************** - * Name: mio283qt2_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int mio283qt2_getpower(FAR struct lcd_dev_s *dev) -{ - lcdvdbg("power: %d\n", 0); - return g_lcddev.power; -} - -/************************************************************************************** - * Name: mio283qt2_poweroff - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int mio283qt2_poweroff(FAR struct mio283qt2_lcd_s *lcd) -{ - /* Set the backlight off */ - - lcd->backlight(lcd, 0); - - /* Turn the display off */ - - mio283qt2_putreg(lcd, 0x28, 0x0000); /* GON=0, DTE=0, D=0 */ - - /* Remember the power off state */ - - g_lcddev.power = 0; - return OK; -} - -/************************************************************************************** - * Name: mio283qt2_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int mio283qt2_setpower(FAR struct lcd_dev_s *dev, int power) -{ - FAR struct mio283qt2_dev_s *priv = (FAR struct mio283qt2_dev_s *)dev; - FAR struct mio283qt2_lcd_s *lcd = priv->lcd; - - lcdvdbg("power: %d\n", power); - DEBUGASSERT((unsigned)power <= CONFIG_LCD_MAXPOWER); - - /* Set new power level */ - - if (power > 0) - { - /* Set the backlight level */ - - lcd->backlight(lcd, power); - - /* Then turn the display on: - * D=ON(3) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0 - */ - - /* Display on */ - - mio283qt2_putreg(lcd, 0x28, 0x0038); /* GON=1, DTE=1, D=2 */ - up_mdelay(40); - mio283qt2_putreg(lcd, 0x28, 0x003c); /* GON=1, DTE=1, D=3 */ - - g_lcddev.power = power; - } - else - { - /* Turn the display off */ - - mio283qt2_poweroff(lcd); - } - - return OK; -} - -/************************************************************************************** - * Name: mio283qt2_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int mio283qt2_getcontrast(FAR struct lcd_dev_s *dev) -{ - lcdvdbg("Not implemented\n"); - return -ENOSYS; -} - -/************************************************************************************** - * Name: mio283qt2_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int mio283qt2_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast) -{ - lcdvdbg("contrast: %d\n", contrast); - return -ENOSYS; -} - -/************************************************************************************** - * Name: mio283qt2_hwinitialize - * - * Description: - * Initialize the LCD hardware. - * - **************************************************************************************/ - -static inline int mio283qt2_hwinitialize(FAR struct mio283qt2_dev_s *priv) -{ - FAR struct mio283qt2_lcd_s *lcd = priv->lcd; -#ifndef CONFIG_LCD_NOGETRUN - uint16_t id; -#endif - - /* Select the LCD */ - - lcd->select(lcd); - - /* Read the HIMAX ID registger (0x00) */ - -#ifndef CONFIG_LCD_NOGETRUN - id = mio283qt2_readreg(lcd, 0x00); - lcddbg("LCD ID: %04x\n", id); - - /* Check if the ID is for the MIO283QT2 */ - - if (id == HIMAX_ID) -#endif - { - /* Driving ability */ - - mio283qt2_putreg(lcd, 0xea, 0x0000); /* PTBA[15:8] */ - mio283qt2_putreg(lcd, 0xeb, 0x0020); /* PTBA[7:0] */ - mio283qt2_putreg(lcd, 0xec, 0x000c); /* STBA[15:8] */ - mio283qt2_putreg(lcd, 0xed, 0x00c4); /* STBA[7:0] */ - mio283qt2_putreg(lcd, 0xe8, 0x0040); /* OPON[7:0] */ - mio283qt2_putreg(lcd, 0xe9, 0x0038); /* OPON1[7:0] */ - mio283qt2_putreg(lcd, 0xf1, 0x0001); /* OTPS1B */ - mio283qt2_putreg(lcd, 0xf2, 0x0010); /* GEN */ - mio283qt2_putreg(lcd, 0x27, 0x00a3); - - /* Power voltage */ - - mio283qt2_putreg(lcd, 0x1b, 0x001b); /* VRH = 4.65 */ - mio283qt2_putreg(lcd, 0x1a, 0x0001); /* BT */ - mio283qt2_putreg(lcd, 0x24, 0x002f); /* VMH */ - mio283qt2_putreg(lcd, 0x25, 0x0057); /* VML */ - - /* Vcom offset */ - - mio283qt2_putreg(lcd, 0x23, 0x008d); /* For flicker adjust */ - - /* Power on */ - - mio283qt2_putreg(lcd, 0x18, 0x0036); - mio283qt2_putreg(lcd, 0x19, 0x0001); /* Start oscillator */ - mio283qt2_putreg(lcd, 0x01, 0x0000); /* Wakeup */ - mio283qt2_putreg(lcd, 0x1f, 0x0088); - up_mdelay(5); - mio283qt2_putreg(lcd, 0x1f, 0x0080); - up_mdelay(5); - mio283qt2_putreg(lcd, 0x1f, 0x0090); - up_mdelay(5); - mio283qt2_putreg(lcd, 0x1f, 0x00d0); - up_mdelay(5); - - /* Gamma 2.8 setting */ - - mio283qt2_putreg(lcd, 0x40, 0x0000); - mio283qt2_putreg(lcd, 0x41, 0x0000); - mio283qt2_putreg(lcd, 0x42, 0x0001); - mio283qt2_putreg(lcd, 0x43, 0x0013); - mio283qt2_putreg(lcd, 0x44, 0x0010); - mio283qt2_putreg(lcd, 0x45, 0x0026); - mio283qt2_putreg(lcd, 0x46, 0x0008); - mio283qt2_putreg(lcd, 0x47, 0x0051); - mio283qt2_putreg(lcd, 0x48, 0x0002); - mio283qt2_putreg(lcd, 0x49, 0x0012); - mio283qt2_putreg(lcd, 0x4a, 0x0018); - mio283qt2_putreg(lcd, 0x4b, 0x0019); - mio283qt2_putreg(lcd, 0x4c, 0x0014); - - mio283qt2_putreg(lcd, 0x50, 0x0019); - mio283qt2_putreg(lcd, 0x51, 0x002f); - mio283qt2_putreg(lcd, 0x52, 0x002c); - mio283qt2_putreg(lcd, 0x53, 0x003e); - mio283qt2_putreg(lcd, 0x54, 0x003f); - mio283qt2_putreg(lcd, 0x55, 0x003f); - mio283qt2_putreg(lcd, 0x56, 0x002e); - mio283qt2_putreg(lcd, 0x57, 0x0077); - mio283qt2_putreg(lcd, 0x58, 0x000b); - mio283qt2_putreg(lcd, 0x59, 0x0006); - mio283qt2_putreg(lcd, 0x5a, 0x0007); - mio283qt2_putreg(lcd, 0x5b, 0x000d); - mio283qt2_putreg(lcd, 0x5c, 0x001d); - mio283qt2_putreg(lcd, 0x5d, 0x00cc); - - /* 4K Color Selection */ - - mio283qt2_putreg(lcd, 0x17, 0x0003); - mio283qt2_putreg(lcd, 0x17, 0x0005); /* 0x0005=65k, 0x0006=262k */ - - /* Panel characteristics */ - - mio283qt2_putreg(lcd, 0x36, 0x0000); - - /* Display Setting */ - - mio283qt2_putreg(lcd, 0x01, 0x0000); /* IDMON=0, INVON=0, NORON=0, PTLON=0 */ - -#if defined(CONFIG_LCD_LANDSCAPE) - mio283qt2_putreg(lcd, 0x16, 0x00a8); /* MY=1, MX=0, MV=1, ML=0, BGR=1 */ -#elif defined(CONFIG_LCD_PORTRAIT) - mio283qt2_putreg(lcd, 0x16, 0x0008); /* MY=0, MX=0, MV=0, ML=0, BGR=1 */ -#elif defined(CONFIG_LCD_RLANDSCAPE) - mio283qt2_putreg(lcd, 0x16, 0x0068); /* MY=0, MX=1, MV=1, ML=0, BGR=1 */ -#elif defined(CONFIG_LCD_RPORTRAIT) - mio283qt2_putreg(lcd, 0x16, 0x00c8); /* MY=1, MX=0, MV=1, ML=0, BGR=1 */ -#endif - - /* Window setting */ - - mio283qt2_setarea(lcd, 0, 0, (MIO283QT2_XRES-1), (MIO283QT2_YRES-1)); - return OK; - } -#ifndef CONFIG_LCD_NOGETRUN - else - { - lcddbg("Unsupported LCD type\n"); - return -ENODEV; - } -#endif - - /* De-select the LCD */ - - lcd->deselect(lcd); -} - - /************************************************************************************* - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: mio283qt2_lcdinitialize - * - * Description: - * Initialize the LCD video hardware. The initial state of the LCD is fully - * initialized, display memory cleared, and the LCD ready to use, but with the power - * setting at 0 (full off). - * - **************************************************************************************/ - -FAR struct lcd_dev_s *mio283qt2_lcdinitialize(FAR struct mio283qt2_lcd_s *lcd) -{ - int ret; - - lcdvdbg("Initializing\n"); - - /* If we ccould support multiple MIO283QT2 devices, this is where we would allocate - * a new driver data structure... but we can't. Why not? Because of a bad should - * the form of the getrun() and putrun methods. - */ - - FAR struct mio283qt2_dev_s *priv = &g_lcddev; - - /* Initialize the driver data structure */ - - priv->dev.getvideoinfo = mio283qt2_getvideoinfo; - priv->dev.getplaneinfo = mio283qt2_getplaneinfo; - priv->dev.getpower = mio283qt2_getpower; - priv->dev.setpower = mio283qt2_setpower; - priv->dev.getcontrast = mio283qt2_getcontrast; - priv->dev.setcontrast = mio283qt2_setcontrast; - priv->lcd = lcd; - - /* Configure and enable LCD */ - - ret = mio283qt2_hwinitialize(priv); - if (ret == OK) - { - /* Clear the display (setting it to the color 0=black) */ - - mio283qt2_clear(&priv->dev, 0); - - /* Turn the display off */ - - mio283qt2_poweroff(lcd); - return &g_lcddev.dev; - } - - return NULL; -} - -/************************************************************************************** - * Name: mio283qt2_clear - * - * Description: - * This is a non-standard LCD interface just for the stm3240g-EVAL board. Because - * of the various rotations, clearing the display in the normal way by writing a - * sequences of runs that covers the entire display can be very slow. Here the - * display is cleared by simply setting all GRAM memory to the specified color. - * - **************************************************************************************/ - -void mio283qt2_clear(FAR struct lcd_dev_s *dev, uint16_t color) -{ - FAR struct mio283qt2_dev_s *priv = (FAR struct mio283qt2_dev_s *)dev; - FAR struct mio283qt2_lcd_s *lcd = priv->lcd; - uint32_t i; - - /* Select the LCD and set the drawring area */ - - lcd->select(lcd); - mio283qt2_setarea(lcd, 0, 0, (MIO283QT2_XRES-1), (MIO283QT2_YRES-1)); - - /* Prepare to write GRAM data */ - - mio283qt2_gramselect(lcd); - - /* Copy color into all of GRAM. Orientation does not matter in this case. */ - - for (i = 0; i < MIO283QT2_XRES * MIO283QT2_YRES; i++) - { - mio283qt2_gramwrite(lcd, color); - } - - /* De-select the LCD */ - - lcd->deselect(lcd); -} - -#endif /* CONFIG_LCD_MIO283QT2 */ diff --git a/nuttx/drivers/lcd/nokia6100.c b/nuttx/drivers/lcd/nokia6100.c deleted file mode 100644 index 7354b8a91..000000000 --- a/nuttx/drivers/lcd/nokia6100.c +++ /dev/null @@ -1,1230 +0,0 @@ -/************************************************************************************** - * drivers/lcd/nokia6100.c - * Nokia 6100 LCD Display Driver - * - * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * "Nokia 6100 LCD Display Driver," Revision 1, James P. Lynch ("Nokia 6100 LCD - * Display Driver.pdf") - * "S1D15G0D08B000," Seiko Epson Corportation, 2002. - * "Data Sheet, PCF8833 STN RGB 132x132x3 driver," Phillips, 2003 Feb 14. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_NOKIA6100_PCF8833 -# include "pcf8833.h" -#endif -#ifdef CONFIG_NOKIA6100_S1D15G10 -# include "s1d15g10.h" -#endif - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ - -/* Configuration **********************************************************************/ -/* Verify that all configuration requirements have been met */ - -/* Nokia 6100 Configuration Settings: - * - * CONFIG_NOKIA6100_SPIMODE - Controls the SPI mode - * CONFIG_NOKIA6100_FREQUENCY - Define to use a different bus frequency - * CONFIG_NOKIA6100_NINTERFACES - Specifies the number of physical Nokia 6100 devices that - * will be supported. - * CONFIG_NOKIA6100_BPP - Device supports 8, 12, and 16 bits per pixel. - * CONFIG_NOKIA6100_S1D15G10 - Selects the Epson S1D15G10 display controller - * CONFIG_NOKIA6100_PCF8833 - Selects the Phillips PCF8833 display controller - * CONFIG_NOKIA6100_BLINIT - Initial backlight setting - * - * The following may need to be tuned for your hardware: - * CONFIG_NOKIA6100_INVERT - Display inversion, 0 or 1, Default: 1 - * CONFIG_NOKIA6100_MY - Display row direction, 0 or 1, Default: 0 - * CONFIG_NOKIA6100_MX - Display column direction, 0 or 1, Default: 1 - * CONFIG_NOKIA6100_V - Display address direction, 0 or 1, Default: 0 - * CONFIG_NOKIA6100_ML - Display scan direction, 0 or 1, Default: 0 - * CONFIG_NOKIA6100_RGBORD - Display RGB order, 0 or 1, Default: 0 - * - * Required LCD driver settings: - * CONFIG_LCD_NOKIA6100 - Enable Nokia 6100 support - * CONFIG_LCD_MAXCONTRAST - must be 63 with the Epson controller and 127 with - * the Phillips controller. - * CONFIG_LCD_MAXPOWER - Maximum value of backlight setting. The backlight control is - * managed outside of the 6100 driver so this value has no meaning to the driver. - */ - -/* Mode 0,0 should be use. However, somtimes you need to tinker with these things. */ - -#ifndef CONFIG_NOKIA6100_SPIMODE -# define CONFIG_NOKIA6100_SPIMODE SPIDEV_MODE0 -#endif - -/* Default frequency: 1Mhz */ - -#ifndef CONFIG_NOKIA6100_FREQUENCY -# define CONFIG_NOKIA6100_FREQUENCY 1000000 -#endif - -/* CONFIG_NOKIA6100_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_NOKIA6100_NINTERFACES -# define CONFIG_NOKIA6100_NINTERFACES 1 -#endif - -#if CONFIG_NOKIA6100_NINTERFACES != 1 -# error "This implementation supports only a single LCD device" -#endif - -/* Only support for 8 and 12 BPP currently implemented */ - -#if !defined(CONFIG_NOKIA6100_BPP) -# warning "Assuming 8BPP" -# define CONFIG_NOKIA6100_BPP 8 -#endif - -#if CONFIG_NOKIA6100_BPP != 8 && CONFIG_NOKIA6100_BPP != 12 -# if CONFIG_NOKIA6100_BPP == 16 -# error "Support for 16BPP no yet implemented" -# else -# error "LCD supports only 8, 12, and 16BPP" -# endif -#endif - -#if CONFIG_NOKIA6100_BPP == 8 -# ifdef CONFIG_NX_DISABLE_8BPP -# warning "8-bit pixel support needed" -# endif -#elif CONFIG_NOKIA6100_BPP == 12 -# if defined(CONFIG_NX_DISABLE_12BPP) || !defined(CONFIG_NX_PACKEDMSFIRST) -# warning "12-bit, big-endian pixel support needed" -# endif -#elif CONFIG_NOKIA6100_BPP == 16 -# ifdef CONFIG_NX_DISABLE_16BPP -# warning "16-bit pixel support needed" -# endif -#endif - -/* Exactly one LCD controller must be selected. "The Olimex boards have both display - * controllers possible; if the LCD has a GE-12 sticker on it, it’s a Philips PCF8833. - * If it has a GE-8 sticker, it’s an Epson controller." - */ - -#if defined(CONFIG_NOKIA6100_S1D15G10) && defined(CONFIG_NOKIA6100_PCF8833) -# error "Both CONFIG_NOKIA6100_S1D15G10 and CONFIG_NOKIA6100_PCF8833 are defined" -#endif - -#if !defined(CONFIG_NOKIA6100_S1D15G10) && !defined(CONFIG_NOKIA6100_PCF8833) -# error "One of CONFIG_NOKIA6100_S1D15G10 or CONFIG_NOKIA6100_PCF8833 must be defined" -#endif - -/* Delay geometry defaults */ - -#ifndef CONFIG_NOKIA6100_INVERT -# define CONFIG_NOKIA6100_INVERT 1 -#endif - -#ifndef CONFIG_NOKIA6100_MY -# define CONFIG_NOKIA6100_MY 0 -#endif - -#ifndef CONFIG_NOKIA6100_MX -# define CONFIG_NOKIA6100_MX 1 -#endif - -#ifndef CONFIG_NOKIA6100_V -# define CONFIG_NOKIA6100_V 0 -#endif - -#ifndef CONFIG_NOKIA6100_ML -# define CONFIG_NOKIA6100_ML 0 -#endif - -#ifndef CONFIG_NOKIA6100_RGBORD -# define CONFIG_NOKIA6100_RGBORD 0 -#endif - -/* Check contrast selection */ - -#ifdef CONFIG_NOKIA6100_S1D15G10 - -# if !defined(CONFIG_LCD_MAXCONTRAST) -# define CONFIG_LCD_MAXCONTRAST 63 -# endif -# if CONFIG_LCD_MAXCONTRAST != 63 -# error "CONFIG_LCD_MAXCONTRAST must be 63 with the Epson LCD controller" -# endif -# define NOKIA_DEFAULT_CONTRAST 32 - -#else /* CONFIG_NOKIA6100_PCF8833 */ - -# if !defined(CONFIG_LCD_MAXCONTRAST) -# define CONFIG_LCD_MAXCONTRAST 127 -# endif -# if CONFIG_LCD_MAXCONTRAST != 127 -# error "CONFIG_LCD_MAXCONTRAST must be 127 with the Phillips LCD controller" -# endif -# define NOKIA_DEFAULT_CONTRAST 48 - -#endif - -/* Check initial backlight setting */ - -#ifndef CONFIG_NOKIA6100_BLINIT -# define CONFIG_NOKIA6100_BLINIT (NOKIA_DEFAULT_CONTRAST/3) -#endif - -/* Word width must be 9 bits */ - -#if defined(CONFIG_NOKIA6100_WORDWIDTH) && CONFIG_NOKIA6100_WORDWIDTH != 9 -# error "CONFIG_NOKIA6100_WORDWIDTH must be 9" -#endif -#ifndef CONFIG_NOKIA6100_WORDWIDTH -# define CONFIG_NOKIA6100_WORDWIDTH 9 -#endif - -/* If bit 9 is set, the byte is data; clear for commands */ - -#define NOKIA_LCD_DATA (1 << 8) - -/* Define CONFIG_LCD_REGDEBUG to enable register-level debug output. - * (Verbose debug must also be enabled) - */ - -#ifndef CONFIG_DEBUG -# undef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_GRAPHICS -#endif - -#ifndef CONFIG_DEBUG_VERBOSE -# undef CONFIG_LCD_REGDEBUG -#endif - -/* Controller independent definitions *************************************************/ - -#ifdef CONFIG_NOKIA6100_PCF8833 -# define LCD_NOP PCF8833_NOP -# define LCD_RAMWR PCF8833_RAMWR -# define LCD_PASET PCF8833_PASET -# define LCD_CASET PCF8833_CASET -#endif -#ifdef CONFIG_NOKIA6100_S1D15G10 -# define LCD_NOP S1D15G10_NOP -# define LCD_RAMWR S1D15G10_RAMWR -# define LCD_PASET S1D15G10_PASET -# define LCD_CASET S1D15G10_CASET -#endif - -/* Color Properties *******************************************************************/ - -/* Display Resolution */ - -#define NOKIA_XRES 132 -#define NOKIA_YRES 132 - -/* Color depth and format */ - -#if CONFIG_NOKIA6100_BPP == 8 -# define NOKIA_BPP 8 -# define NOKIA_COLORFMT FB_FMT_RGB8_332 -# define NOKIA_STRIDE NOKIA_XRES -# define NOKIA_PIX2BYTES(p) (p) -#elif CONFIG_NOKIA6100_BPP == 12 -# define NOKIA_BPP 12 -# define NOKIA_COLORFMT FB_FMT_RGB12_444 -# define NOKIA_STRIDE ((3*NOKIA_XRES+1)/2) -# define NOKIA_PIX2BYTES(p) ((3*(p)+1)/2) -#elif CONFIG_NOKIA6100_BPP == 16 -# define NOKIA_BPP 16 -# define NOKIA_COLORFMT FB_FMT_RGB16_565 -# define NOKIA_STRIDE (2*NOKIA_XRES) -# define NOKIA_PIX2BYTES(p) (2*(p)) -#endif - -/* Handle any potential strange behavior at edges */ - -#if 0 /* REVISIT */ -#define NOKIA_PGBIAS 2 /* May not be necessary */ -#define NOKIA_COLBIAS 0 -#define NOKIA_XBIAS 2 /* May not be necessary, if so need to subtract from XRES */ -#define NOKIA_YBIAS 0 -#else -#define NOKIA_PGBIAS 0 -#define NOKIA_COLBIAS 0 -#define NOKIA_XBIAS 0 -#define NOKIA_YBIAS 0 -#endif - -#define NOKIA_ENDPAGE 131 -#define NOKIA_ENDCOL 131 - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_LCD_REGDEBUG -# define lcddbg(format, arg...) llvdbg(format, ##arg) -#else -# define lcddbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct nokia_dev_s -{ - /* Publically visible device structure */ - - struct lcd_dev_s dev; - - /* Private LCD-specific information follows */ - - FAR struct spi_dev_s *spi; /* Contained SPI driver instance */ - uint8_t contrast; /* Current contrast setting */ - uint8_t power; /* Current power (backlight) setting */ -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ - -/* SPI support */ - -static inline void nokia_configspi(FAR struct spi_dev_s *spi); -#ifdef CONFIG_SPI_OWNBUS -static inline void nokia_select(FAR struct spi_dev_s *spi); -static inline void nokia_deselect(FAR struct spi_dev_s *spi); -#else -static void nokia_select(FAR struct spi_dev_s *spi); -static void nokia_deselect(FAR struct spi_dev_s *spi); -#endif -static void nokia_sndcmd(FAR struct spi_dev_s *spi, const uint8_t cmd); -static void nokia_cmdarray(FAR struct spi_dev_s *spi, int len, const uint8_t *cmddata); -static void nokia_clrram(FAR struct spi_dev_s *spi); - -/* LCD Data Transfer Methods */ - -static int nokia_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels); -static int nokia_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int nokia_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int nokia_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int nokia_getpower(struct lcd_dev_s *dev); -static int nokia_setpower(struct lcd_dev_s *dev, int power); -static int nokia_getcontrast(struct lcd_dev_s *dev); -static int nokia_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); - -/* Initialization */ - -static int nokia_initialize(struct nokia_dev_s *priv); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - -#if CONFIG_NOKIA6100_BPP == 8 -static uint8_t g_runbuffer[NOKIA_XRES]; -#elif CONFIG_NOKIA6100_BPP == 12 -static uint8_t g_runbuffer[(3*NOKIA_XRES+1)/2]; -#else /* CONFIG_NOKIA6100_BPP == 16 */ -static uint16_t g_runbuffer[NOKIA_XRES]; -#endif - -/* g_rowbuf is another buffer, but used internally by the Nokia 6100 driver in order - * expand the pixel data into 9-bit data needed by the LCD. There are some - * customizations that would eliminate the need for this extra buffer and for the - * extra expansion/copy, but those customizations would require a special, non-standard - * SPI driver that could expand 8- to 9-bit data on the fly. - */ - -static uint16_t g_rowbuf[NOKIA_STRIDE+1]; - -/* Device Driver Data Structures ******************************************************/ - -/* This structure describes the overall LCD video controller */ - -static const struct fb_videoinfo_s g_videoinfo = -{ - .fmt = NOKIA_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - .xres = NOKIA_XRES, /* Horizontal resolution in pixel columns */ - .yres = NOKIA_YRES, /* Vertical resolution in pixel rows */ - .nplanes = 1, /* Number of color planes supported */ -}; - -/* This is the standard, NuttX Plane information object */ - -static const struct lcd_planeinfo_s g_planeinfo = -{ - .putrun = nokia_putrun, /* Put a run into LCD memory */ - .getrun = nokia_getrun, /* Get a run from LCD memory */ - .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */ - .bpp = NOKIA_BPP, /* Bits-per-pixel */ -}; - -/* This is the standard, NuttX LCD driver object */ - -static struct nokia_dev_s g_lcddev = -{ - .dev = - { - /* LCD Configuration */ - - .getvideoinfo = nokia_getvideoinfo, - .getplaneinfo = nokia_getplaneinfo, - - /* LCD RGB Mapping -- Not supported */ - /* Cursor Controls -- Not supported */ - - /* LCD Specific Controls */ - - .getpower = nokia_getpower, - .setpower = nokia_setpower, - .getcontrast = nokia_getcontrast, - .setcontrast = nokia_setcontrast, - }, -}; - -/* LCD Command Strings ****************************************************************/ - -#ifdef CONFIG_NOKIA6100_S1D15G10 -/* Display control: - * P1: Specifies the CL dividing ratio, F1 and F2 drive-pattern switching period. - * P2: Specifies the duty of the module on block basis - * P3: Specify number of lines to be inversely highlighted on LCD panel - * P4: 0: Dispersion P40= 1: Non-dispersion - */ - -#if 1 // CONFIG_NOKIA6100_BPP == 12 -static const uint8_t g_disctl[] = -{ - S1D15G10_DISCTL, /* Display control */ - DISCTL_CLDIV_2|DISCTL_PERIOD_8, /* P1: Divide clock by 2; switching period = 8 */ -//DISCTL_CLDIV_NONE|DISCTL_PERIOD_8, /* P1: No clock division; switching period = 8 */ - 32, /* P2: nlines/4 - 1 = 132/4 - 1 = 32 */ - 0, /* P3: No inversely highlighted lines */ - 0 /* P4: No disperion */ -}; -#else /* CONFIG_NOKIA6100_BPP == 8 */ -static const uint8_t g_disctl[] = -{ - S1D15G10_DISCTL, /* Display control */ - DISCTL_CLDIV_2|DISCTL_PERIOD_FLD, /* P1: Divide clock by 2; switching period = field */ - 32, /* P2: nlines/4 - 1 = 132/4 - 1 = 32 */ - 0, /* P3: No inversely highlighted lines */ - 0 /* P4: No disperion */ -}; -#endif - -/* Common scan direction: - * P1: Cpecify the common output scan direction. - */ - -static const uint8_t g_comscn[] = -{ - S1D15G10_COMSCN, /* Common scan direction */ - 1 /* 0x01 = Scan 1->68, 132<-69 */ -}; - -/* Power control: - * P1: Turn on or off the liquid crystal driving power circuit, booster/step-down - * circuits and voltage follower circuit. - */ - -static const uint8_t g_pwrctr[] = -{ - S1D15G10_PWRCTR, /* Power control */ - PWCTR_REFVOLTAGE|PWCTR_REGULATOR|PWCTR_BOOSTER2|PWCTR_BOOSTER1 -}; - -/* Data control: - * P1: Specify the normal or inverse display of the page address and also to specify - * the page address scanning direction - * P2: RGB sequence - * P3: Grayscale setup - */ - -static const uint8_t g_datctl[] = -{ - S1D15G10_DATCTL, /* Data control */ - 0 -#if CONFIG_NOKIA6100_MY != 0 /* Display row direction */ - |DATCTL_PGADDR_INV /* Page address inverted */ -#endif -#if CONFIG_NOKIA6100_MX != 0 /* Display column direction */ - |DATCTL_COLADDR_REV /* Column address reversed */ -#endif -#if CONFIG_NOKIA6100_V != 0 /* Display address direction */ - |DATCTL_ADDR_PGDIR /* Address scan in page direction */ -#endif - , -#if CONFIG_NOKIA6100_RGBORD != 0 - DATCTL_BGR, /* RGB->BGR */ -#else - 0, /* RGB->RGB */ -#endif -#if CONFIG_NOKIA6100_BPP == 8 - DATCTL_8GRAY /* Selects 8-bit color */ -#elif CONFIG_NOKIA6100_BPP == 12 - DATCTL_16GRAY_A /* Selects 16-bit color, Type A */ -#else -# error "16-bit mode not yet implemented" -#endif -}; - -/* Voltage control (contrast setting): - * P1: Volume value - * P2: Resistance ratio - * (May need to be tuned for individual displays) - */ - -static const uint8_t g_volctr[] = -{ - S1D15G10_VOLCTR, /* Volume control */ - NOKIA_DEFAULT_CONTRAST, /* Volume value */ - 2 /* Resistance ratio */ -}; - -/* 256-color position set (RGBSET8) */ - -#if CONFIG_NOKIA6100_BPP == 8 -static const uint8_t g_rgbset8[] = -{ - S1D15G10_RGBSET8, /* 256-color position set */ - 0, 2, 4, 6, 9, 11, 13, 15, /* Red tones */ - 0, 2, 4, 6, 9, 11, 13, 15, /* Green tones */ - 0, 5, 10, 15 /* Blue tones */ -}; -#endif - -/* Page address set (PASET) */ - -static const uint8_t g_paset[] = -{ - S1D15G10_PASET, /* Page start address set */ - NOKIA_PGBIAS, - 131 -}; - -/* Column address set (CASET) */ - -static const uint8_t g_caset[] = -{ - S1D15G10_CASET, /* Column start address set */ - NOKIA_COLBIAS, - 131 -}; -#endif /* CONFIG_NOKIA6100_S1D15G10 */ - -#ifdef CONFIG_NOKIA6100_PCF8833 - -/* Color interface pixel format (COLMOD) */ - -#if CONFIG_NOKIA6100_BPP == 12 -static const uint8_t g_colmod[] = -{ - PCF8833_COLMOD, /* Color interface pixel format */ - PCF8833_FMT_12BPS /* 12 bits-per-pixel */ -}; -#else /* CONFIG_NOKIA6100_BPP == 8 */ -static const uint8_t g_colmod[] = -{ - PCF8833_COLMOD, /* Color interface pixel format */ - PCF8833_FMT_8BPS /* 8 bits-per-pixel */ -}; -#endif - -/* Memory data access control(MADCTL) */ - -static const uint8_t g_madctl[] = -{ - PCF8833_MADCTL, /* Memory data access control*/ - 0 -#ifdef CONFIG_NOKIA6100_RGBORD != 0 - |MADCTL_RGB /* RGB->BGR */ -#endif -#ifdef CONFIG_NOKIA6100_MY != 0 /* Display row direction */ - |MADCTL_MY /* Mirror Y */ -#endif -#ifdef CONFIG_NOKIA6100_MX != 0 /* Display column direction */ - |MADCTL_MX /* Mirror X */ -#endif -#ifdef CONFIG_NOKIA6100_V != 0 /* Display address direction */ - |MADCTL_V /* ertical RAM write; in Y direction */ -#endif -#ifdef CONFIG_NOKIA6100_ML != 0 /* Display scan direction */ - |MADCTL_LAO /* Line address order bottom to top */ -#endif -}; - -/* Set contrast (SETCON) */ - -static const uint8_t g_setcon[] = -{ - PCF8833_SETCON, /* Set contrast */ - NOKIA_DEFAULT_CONTRAST -}; - -#endif /* CONFIG_NOKIA6100_PCF8833 */ - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Function: nokia_configspi - * - * Description: - * Configure the SPI for use with the Nokia 6100 - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -static inline void nokia_configspi(FAR struct spi_dev_s *spi) -{ - lcddbg("Mode: %d Bits: %d Frequency: %d\n", - CONFIG_NOKIA6100_SPIMODE, CONFIG_NOKIA6100_WORDWIDTH, CONFIG_NOKIA6100_FREQUENCY); - - /* Configure SPI for the Nokia 6100. But only if we own the SPI bus. Otherwise, don't - * bother because it might change. - */ - -#ifdef CONFIG_SPI_OWNBUS - SPI_SETMODE(spi, CONFIG_NOKIA6100_SPIMODE); - SPI_SETBITS(spi, CONFIG_NOKIA6100_WORDWIDTH); - SPI_SETFREQUENCY(spi, CONFIG_NOKIA6100_FREQUENCY) -#endif -} - -/************************************************************************************** - * Function: nokia_select - * - * Description: - * Select the SPI, locking and re-configuring if necessary - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void nokia_select(FAR struct spi_dev_s *spi) -{ - /* We own the SPI bus, so just select the chip */ - - lcddbg("SELECTED\n"); - SPI_SELECT(spi, SPIDEV_DISPLAY, true); -} -#else -static void nokia_select(FAR struct spi_dev_s *spi) -{ - /* Select Nokia 6100 chip (locking the SPI bus in case there are multiple - * devices competing for the SPI bus - */ - - lcddbg("SELECTED\n"); - SPI_LOCK(spi, true); - SPI_SELECT(spi, SPIDEV_DISPLAY, true); - - /* Now make sure that the SPI bus is configured for the Nokia 6100 (it - * might have gotten configured for a different device while unlocked) - */ - - SPI_SETMODE(spi, CONFIG_NOKIA6100_SPIMODE); - SPI_SETBITS(spi, CONFIG_NOKIA6100_WORDWIDTH); - SPI_SETFREQUENCY(spi, CONFIG_NOKIA6100_FREQUENCY); -} -#endif - -/************************************************************************************** - * Function: nokia_deselect - * - * Description: - * De-select the SPI - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void nokia_deselect(FAR struct spi_dev_s *spi) -{ - /* We own the SPI bus, so just de-select the chip */ - - lcddbg("DE-SELECTED\n"); - SPI_SELECT(spi, SPIDEV_DISPLAY, false); -} -#else -static void nokia_deselect(FAR struct spi_dev_s *spi) -{ - /* De-select Nokia 6100 chip and relinquish the SPI bus. */ - - lcddbg("DE-SELECTED\n"); - SPI_SELECT(spi, SPIDEV_DISPLAY, false); - SPI_LOCK(spi, false); -} -#endif - -/************************************************************************************** - * Name: nokia_sndcmd - * - * Description: - * Send a 1-byte command. - * - **************************************************************************************/ - -static void nokia_sndcmd(FAR struct spi_dev_s *spi, const uint8_t cmd) -{ - /* Select the LCD */ - - lcddbg("cmd: %02x\n", cmd); - nokia_select(spi); - - /* Send the command. Bit 8 == 0 denotes a command */ - - (void)SPI_SEND(spi, (uint16_t)cmd); - - /* De-select the LCD */ - - nokia_deselect(spi); -} - -/************************************************************************************** - * Name: nokia_cmddata - * - * Description: - * Send a 1-byte command followed by datlen data bytes. - * - **************************************************************************************/ - -static void nokia_cmddata(FAR struct spi_dev_s *spi, uint8_t cmd, int datlen, - const uint8_t *data) -{ - uint16_t *rowbuf = g_rowbuf; - int i; - - lcddbg("cmd: %02x datlen: %d\n", cmd, datlen); - DEBUGASSERT(datlen <= NOKIA_STRIDE); - - /* Copy the command into the line buffer. Bit 8 == 0 denotes a command. */ - - *rowbuf++ = cmd; - - /* Copy any data after the command into the line buffer */ - - for (i = 0; i < datlen; i++) - { - /* Bit 8 == 1 denotes data */ - - *rowbuf++ = (uint16_t)*data++ | NOKIA_LCD_DATA; - } - - /* Select the LCD */ - - nokia_select(spi); - - /* Send the line buffer. */ - - (void)SPI_SNDBLOCK(spi, g_rowbuf, datlen+1); - - /* De-select the LCD */ - - nokia_deselect(spi); -} - -/************************************************************************************** - * Name: nokia_ramwr - * - * Description: - * Send a RAMWR command followed by datlen data bytes. - * - **************************************************************************************/ - -static void nokia_ramwr(FAR struct spi_dev_s *spi, int datlen, const uint8_t *data) -{ - nokia_cmddata(spi, LCD_RAMWR, datlen, data); -} - -/************************************************************************************** - * Name: nokia_cmdarray - * - * Description: - * Send a RAMWR command followed by len-1 data bytes. - * - **************************************************************************************/ - -static void nokia_cmdarray(FAR struct spi_dev_s *spi, int len, const uint8_t *cmddata) -{ -#ifdef CONFIG_LCD_REGDEBUG - int i; - - for (i = 0; i < len; i++) - { - lcddbg("cmddata[%d]: %02x\n", i, cmddata[i]); - } -#endif - nokia_cmddata(spi, cmddata[0], len-1, &cmddata[1]); -} - -/************************************************************************************** - * Name: nokia_clrram - * - * Description: - * Send a 1-byte command followed by len-1 data bytes. - * - **************************************************************************************/ - -static void nokia_clrram(FAR struct spi_dev_s *spi) -{ - uint16_t *rowbuf = g_rowbuf; - int i; - - /* Set all zero data in the line buffer */ - - for (i = 0; i < NOKIA_STRIDE; i++) - { - /* Bit 8 == 1 denotes data */ - - *rowbuf++ = NOKIA_LCD_DATA; - } - - /* Select the LCD and send the RAMWR command */ - - nokia_select(spi); - SPI_SEND(spi, LCD_RAMWR); - - /* Send the line buffer, once for each row. */ - - for (i = 0; i < NOKIA_YRES; i++) - { - (void)SPI_SNDBLOCK(spi, g_rowbuf, NOKIA_STRIDE); - } - - /* De-select the LCD */ - - nokia_deselect(spi); -} - -/************************************************************************************** - * Name: nokia_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD: - * - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int nokia_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - struct nokia_dev_s *priv = &g_lcddev; - FAR struct spi_dev_s *spi = priv->spi; - uint16_t cmd[3]; - - gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - -#if NOKIA_XBIAS > 0 - col += NOKIA_XBIAS; -#endif -#if NOKIA_YBIAS > 0 - row += NOKIA_YBIAS; -#endif - DEBUGASSERT(buffer && col >=0 && (col + npixels) <= NOKIA_XRES && row >= 0 && row < NOKIA_YRES); - - /* Set up to write the run. */ - - nokia_select(spi); - cmd[0] = LCD_PASET; - cmd[1] = col | NOKIA_LCD_DATA; - cmd[2] = NOKIA_ENDPAGE | NOKIA_LCD_DATA; - (void)SPI_SNDBLOCK(spi, cmd, 3); - nokia_deselect(spi); - - /* De-select the LCD */ - - nokia_select(spi); - cmd[0] = LCD_CASET; - cmd[1] = row | NOKIA_LCD_DATA; - cmd[2] = NOKIA_ENDCOL | NOKIA_LCD_DATA; - (void)SPI_SNDBLOCK(spi, cmd, 3); - nokia_deselect(spi); - - /* Then send the run */ - - nokia_ramwr(spi, NOKIA_PIX2BYTES(npixels), buffer); - return OK; -} - -/************************************************************************************** - * Name: nokia_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int nokia_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ - gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); - - /* At present, this is a write-only LCD driver */ - -#warning "Not implemented" - return -ENOSYS; -} - -/************************************************************************************** - * Name: nokia_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int nokia_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", - g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes); - memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: nokia_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int nokia_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - DEBUGASSERT(dev && pinfo && planeno == 0); - gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp); - memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: nokia_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int nokia_getpower(struct lcd_dev_s *dev) -{ - struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; - gvdbg("power: %d\n", priv->power); - return priv->power; -} - -/************************************************************************************** - * Name: nokia_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int nokia_setpower(struct lcd_dev_s *dev, int power) -{ - struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; - int ret; - - gvdbg("power: %d\n", power); - DEBUGASSERT(power <= CONFIG_LCD_MAXPOWER); - - /* Set new power level. The backlight power is controlled outside of the LCD - * assembly and must be managmed by board-specific logic. - */ - - ret = nokia_backlight(power); - if (ret == OK) - { - priv->power = power; - } - return ret; -} - -/************************************************************************************** - * Name: nokia_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int nokia_getcontrast(struct lcd_dev_s *dev) -{ - struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; - gvdbg("contrast: %d\n", priv->contrast); - return priv->contrast; -} - -/************************************************************************************** - * Name: nokia_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int nokia_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) -{ - struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; - - if (contrast < CONFIG_LCD_MAXCONTRAST) - { -#ifdef CONFIG_NOKIA6100_S1D15G10 - while (priv->contrast < contrast) - { - nokia_sndcmd(priv->spi, S1D15G10_VOLUP); - priv->contrast++; - } - while (priv->contrast > contrast) - { - nokia_sndcmd(priv->spi, S1D15G10_VOLDOWN); - priv->contrast--; - } -#else /* CONFIG_NOKIA6100_PCF8833 */ - uint8_t cmd[2]; - - cmd[0] = PCF8833_SETCON; - cmd[1] = priv->contrast; - nokia_sndarry(priv->spi, 2, cmd); - priv->contrast = contrast; -#endif - } - - gvdbg("contrast: %d\n", contrast); - return -ENOSYS; -} - -/************************************************************************************** - * Name: nokia_initialize - * - * Description: - * Initialize the LCD controller. - * - **************************************************************************************/ - -#ifdef CONFIG_NOKIA6100_S1D15G10 -static int nokia_initialize(struct nokia_dev_s *priv) -{ - struct spi_dev_s *spi = priv->spi; - - /* Configure the display */ - - nokia_cmdarray(spi, sizeof(g_disctl), g_disctl); /* Display control */ - nokia_cmdarray(spi, sizeof(g_comscn), g_comscn); /* Common scan direction */ - nokia_sndcmd(spi, S1D15G10_OSCON); /* Internal oscilator ON */ - nokia_sndcmd(spi, S1D15G10_SLPOUT); /* Sleep out */ - nokia_cmdarray(spi, sizeof(g_volctr), g_volctr); /* Volume control (contrast) */ - nokia_cmdarray(spi, sizeof(g_pwrctr), g_pwrctr); /* Turn on voltage regulators */ - up_mdelay(100); -#ifdef CONFIG_NOKIA6100_INVERT - nokia_sndcmd(spi, S1D15G10_DISINV); /* Invert display */ -#else - nokia_sndcmd(spi, S1D15G10_DISNOR); /* Normal display */ -#endif - nokia_cmdarray(spi, sizeof(g_datctl), g_datctl); /* Data control */ -#if CONFIG_NOKIA6100_BPP == 8 - nokia_cmdarray(spi, sizeof(g_rgbset8), g_rgbset8); /* Set up color lookup table */ - nokia_sndcmd(spi, S1D15G10_NOP); -#endif - nokia_cmdarray(spi, sizeof(g_paset), g_paset); /* Page address set */ - nokia_cmdarray(spi, sizeof(g_paset), g_caset); /* Column address set */ - nokia_clrram(spi); - nokia_sndcmd(spi, S1D15G10_DISON); /* Display on */ - return OK; -} -#endif - -#ifdef CONFIG_NOKIA6100_PCF8833 -static int nokia_initialize(struct nokia_dev_s *priv) -{ - struct struct spi_dev_s *spi = priv->spi; - - nokia_sndcmd(spi, PCF8833_SLEEPOUT); /* Exit sleep mode */ - nokia_sndcmd(spi, PCF8833_BSTRON); /* Turn on voltage booster */ -#ifdef CONFIG_NOKIA6100_INVERT - nokia_sndcmd(spi, PCF8833_INVON); /* Invert display */ -#else - nokia_sndcmd(spi, PCF8833_INVOFF); /* Don't invert display */ -#endif - nokia_cmdarray(spi, sizeof(g_madctl), g_madctl); /* Memory data access control */ - nokia_cmdarray(spi, sizeof(g_colmod), g_colmod); /* Color interface pixel format */ - nokia_cmdarray(spi, sizeof(g_setcon), g_setcon); /* Set contrast */ - nokia_sndcmd(spi, PCF8833_NOP); /* No operation */ - nokia_clrram(spi); - nokia_sndcmd(spi, PCF8833_DISPON); /* Display on */ - return OK; -} -#endif /* CONFIG_NOKIA6100_PCF8833 */ - -/************************************************************************************** - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: nokia_lcdinitialize - * - * Description: - * Initialize the NOKIA6100 video hardware. The initial state of the LCD is fully - * initialized, display memory cleared, and the LCD ready to use, but with the power - * setting at 0 (full off == sleep mode). - * - * Input Parameters: - * - * spi - A reference to the SPI driver instance. - * devno - A value in the range of 0 throuh CONFIG_NOKIA6100_NINTERFACES-1. This - * allows support for multiple LCD devices. - * - * Returned Value: - * - * On success, this function returns a reference to the LCD object for the specified - * LCD. NULL is returned on any failure. - * - **************************************************************************************/ - -FAR struct lcd_dev_s *nokia_lcdinitialize(FAR struct spi_dev_s *spi, unsigned int devno) -{ - struct nokia_dev_s *priv = &g_lcddev; - - gvdbg("Initializing\n"); - DEBUGASSERT(devno == 0); - - /* Initialize the driver data structure */ - - priv->spi = spi; /* Save the SPI instance */ - priv->contrast = NOKIA_DEFAULT_CONTRAST; /* Initial contrast setting */ - - /* Configure and enable the LCD controller */ - - nokia_configspi(spi); - if (nokia_initialize(priv) == OK) - { - /* Turn on the backlight */ - - nokia_backlight(CONFIG_NOKIA6100_BLINIT); - return &priv->dev; - } - return NULL; -} diff --git a/nuttx/drivers/lcd/p14201.c b/nuttx/drivers/lcd/p14201.c deleted file mode 100644 index 934d251ca..000000000 --- a/nuttx/drivers/lcd/p14201.c +++ /dev/null @@ -1,1246 +0,0 @@ -/************************************************************************************** - * drivers/lcd/p14201.c - * Driver for RiT P14201 series display (wih sd1329 IC controller) - * - * Copyright (C) 2010, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "sd1329.h" - -#ifdef CONFIG_LCD_P14201 - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ - -/* Configuration **********************************************************************/ - -/* P14201 Configuration Settings: - * - * CONFIG_P14201_SPIMODE - Controls the SPI mode - * CONFIG_P14201_FREQUENCY - Define to use a different bus frequency - * CONFIG_P14201_NINTERFACES - Specifies the number of physical P14201 devices that - * will be supported. - * CONFIG_P14201_FRAMEBUFFER - If defined, accesses will be performed using an in-memory - * copy of the OLEDs GDDRAM. This cost of this buffer is 128 * 96 / 2 = 6Kb. If this - * is defined, then the driver will be fully functional. If not, then it will have the - * following limitations: - * - * - Reading graphics memory cannot be supported, and - * - All pixel writes must be aligned to byte boundaries. - * - * The latter limitation effectively reduces the 128x96 disply to 64x96. - * - * Required LCD driver settings: - * CONFIG_LCD_P14201 - Enable P14201 support - * CONFIG_LCD_MAXCONTRAST should be 255, but any value >0 and <=255 will be accepted. - * CONFIG_LCD_MAXPOWER must be 1 - * - * Required SPI driver settings: - * CONFIG_SPI_CMDDATA - Include support for cmd/data selection. - */ - -#ifndef CONFIG_SPI_CMDDATA -# error "CONFIG_SPI_CMDDATA must be defined in your NuttX configuration" -#endif - -/* The P14201 spec says that is supports SPI mode 0,0 only. However, - * somtimes you need to tinker with these things. - */ - -#ifndef CONFIG_P14201_SPIMODE -# define CONFIG_P14201_SPIMODE SPIDEV_MODE2 -#endif - -/* CONFIG_P14201_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_P14201_NINTERFACES -# define CONFIG_P14201_NINTERFACES 1 -#endif - -#if CONFIG_P14201_NINTERFACES != 1 -# error "This implementation supports only a single OLED device" -#endif - -/* Check contrast selection */ - -#if !defined(CONFIG_LCD_MAXCONTRAST) -# define CONFIG_LCD_MAXCONTRAST 255 -#endif - -#if CONFIG_LCD_MAXCONTRAST <= 0|| CONFIG_LCD_MAXCONTRAST > 255 -# error "CONFIG_LCD_MAXCONTRAST exceeds supported maximum" -#endif - -/* Check power setting */ - -#if !defined(CONFIG_LCD_MAXPOWER) -# define CONFIG_LCD_MAXPOWER 1 -#endif - -#if CONFIG_LCD_MAXPOWER != 1 -# warning "CONFIG_LCD_MAXPOWER exceeds supported maximum" -# undef CONFIG_LCD_MAXPOWER -# define CONFIG_LCD_MAXPOWER 1 -#endif - -/* Color is 4bpp greyscale with leftmost column contained in bits 7:4 */ - -#if defined(CONFIG_NX_DISABLE_4BPP) || !defined(CONFIG_NX_PACKEDMSFIRST) -# warning "4-bit, big-endian pixel support needed" -#endif - -/* Define the CONFIG_LCD_RITDEBUG to enable detailed debug output (stuff you would - * never want to see unless you are debugging this file). - * - * Verbose debug must also be enabled - */ - -#ifndef CONFIG_DEBUG -# undef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_GRAPHICS -#endif - -#ifndef CONFIG_DEBUG_VERBOSE -# undef CONFIG_LCD_RITDEBUG -#endif - -/* Color Properties *******************************************************************/ - -/* Display Resolution */ - -#define RIT_XRES 128 -#define RIT_YRES 96 - -/* Color depth and format */ - -#define RIT_BPP 4 -#define RIT_COLORFMT FB_FMT_Y4 - -/* Default contrast */ - -#define RIT_CONTRAST ((23 * (CONFIG_LCD_MAXCONTRAST+1) / 32) - 1) - -/* Helper Macros **********************************************************************/ - -#define rit_sndcmd(p,b,l) rit_sndbytes(p,b,l,true); -#define rit_snddata(p,b,l) rit_sndbytes(p,b,l,false); - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_LCD_RITDEBUG -# define ritdbg(format, arg...) vdbg(format, ##arg) -#else -# define ritdbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct rit_dev_s -{ - struct lcd_dev_s dev; /* Publically visible device structure */ - FAR struct spi_dev_s *spi; /* Cached SPI device reference */ - uint8_t contrast; /* Current contrast setting */ - bool on; /* true: display is on */ -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ - -/* Low-level SPI helpers */ - -static inline void rit_configspi(FAR struct spi_dev_s *spi); -#ifdef CONFIG_SPI_OWNBUS -static inline void rit_select(FAR struct spi_dev_s *spi); -static inline void rit_deselect(FAR struct spi_dev_s *spi); -#else -static void rit_select(FAR struct spi_dev_s *spi); -static void rit_deselect(FAR struct spi_dev_s *spi); -#endif -static void rit_sndbytes(FAR struct rit_dev_s *priv, FAR const uint8_t *buffer, - size_t buflen, bool cmd); -static void rit_sndcmds(FAR struct rit_dev_s *priv, FAR const uint8_t *table); - -/* LCD Data Transfer Methods */ - -static int rit_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels); -static int rit_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int rit_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int rit_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int rit_getpower(struct lcd_dev_s *dev); -static int rit_setpower(struct lcd_dev_s *dev, int power); -static int rit_getcontrast(struct lcd_dev_s *dev); -static int rit_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - -static uint8_t g_runbuffer[RIT_XRES / 2]; - -/* CONFIG_P14201_FRAMEBUFFER - If defined, accesses will be performed using an in-memory - * copy of the OLEDs GDDRAM. This cost of this buffer is 128 * 64 / 2 = 4Kb. If this - * is defined, then the driver will be full functional. If not, then: - * - * - Reading graphics memory cannot be supported, and - * - All pixel writes must be aligned to byte boundaries. - */ - -#ifdef CONFIG_P14201_FRAMEBUFFER -static uint8_t g_framebuffer[RIT_YRES * RIT_XRES / 2]; -#endif - -/* This structure describes the overall LCD video controller */ - -static const struct fb_videoinfo_s g_videoinfo = -{ - .fmt = RIT_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - .xres = RIT_XRES, /* Horizontal resolution in pixel columns */ - .yres = RIT_YRES, /* Vertical resolution in pixel rows */ - .nplanes = 1, /* Number of color planes supported */ -}; - -/* This is the standard, NuttX Plane information object */ - -static const struct lcd_planeinfo_s g_planeinfo = -{ - .putrun = rit_putrun, /* Put a run into LCD memory */ - .getrun = rit_getrun, /* Get a run from LCD memory */ - .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */ - .bpp = RIT_BPP, /* Bits-per-pixel */ -}; - -/* This is the OLED driver instance (only a single device is supported for now) */ - -static struct rit_dev_s g_oleddev = -{ - .dev = - { - /* LCD Configuration */ - - .getvideoinfo = rit_getvideoinfo, - .getplaneinfo = rit_getplaneinfo, - - /* LCD RGB Mapping -- Not supported */ - /* Cursor Controls -- Not supported */ - - /* LCD Specific Controls */ - - .getpower = rit_getpower, - .setpower = rit_setpower, - .getcontrast = rit_getcontrast, - .setcontrast = rit_setcontrast, - }, -}; - -/* A table of magic initialization commands. This initialization sequence is - * derived from RiT Application Note for the P14201 (with a few tweaked values - * as discovered in some Luminary code examples). - */ - -static const uint8_t g_initcmds[] = -{ - 3, SSD1329_CMD_LOCK, /* Set lock command */ - SSD1329_LOCK_OFF, /* Disable locking */ - SSD1329_NOOP, - 2, SSD1329_SLEEP_ON, /* Matrix display OFF */ - SSD1329_NOOP, - 3, SSD1329_ICON_ALL, /* Set all ICONs to OFF */ - SSD1329_ICON_OFF, /* OFF selection */ - SSD1329_NOOP, - 3, SSD1329_MUX_RATIO, /* Set MUX ratio */ - 95, /* 96 MUX */ - SSD1329_NOOP, - 3, SSD1329_SET_CONTRAST, /* Set contrast */ - RIT_CONTRAST, /* Default contrast */ - SSD1329_NOOP, - 3, SSD1329_PRECHRG2_SPEED, /* Set second pre-charge speed */ - (31 << 1) | SSD1329_PRECHRG2_DBL, /* Pre-charge speed == 32, doubled */ - SSD1329_NOOP, - 3, SSD1329_GDDRAM_REMAP, /* Set GDDRAM re-map */ - (SSD1329_COM_SPLIT| /* Enable COM slip even/odd */ - SSD1329_COM_REMAP| /* Enable COM re-map */ - SSD1329_NIBBLE_REMAP), /* Enable nibble re-map */ - SSD1329_NOOP, - 3, SSD1329_VERT_START, /* Set Display Start Line */ - 0, /* Line = 0 */ - SSD1329_NOOP, - 3, SSD1329_VERT_OFFSET, /* Set Display Offset */ - 0, /* Offset = 0 */ - SSD1329_NOOP, - 2, SSD1329_DISP_NORMAL, /* Display mode normal */ - SSD1329_NOOP, - 3, SSD1329_PHASE_LENGTH, /* Set Phase Length */ - 1 | /* Phase 1 period = 1 DCLK */ - (1 << 4), /* Phase 2 period = 1 DCLK */ - SSD1329_NOOP, - 3, SSD1329_FRAME_FREQ, - 35, /* 35 DCLK's per row */ - SSD1329_NOOP, - 3, SSD1329_DCLK_DIV, /* Set Front Clock Divider / Oscillator Frequency */ - 2 | /* Divide ration = 3 */ - (14 << 4), /* Oscillator Frequency, FOSC, setting */ - SSD1329_NOOP, - 17, SSD1329_GSCALE_LOOKUP, /* Look Up Table for Gray Scale Pulse width */ - 1, 2, 3, 4, 5, /* Value for GS1-5 level Pulse width */ - 6, 8, 10, 12, 14, /* Value for GS6-10 level Pulse width */ - 16, 19, 22, 26, 30, /* Value for GS11-15 level Pulse width */ - SSD1329_NOOP, - 3, SSD1329_PRECHRG2_PERIOD, /* Set Second Pre-charge Period */ - 1, /* 1 DCLK */ - SSD1329_NOOP, - 3, SSD1329_PRECHRG1_VOLT, /* Set First Precharge voltage, VP */ - 0x3f, /* 1.00 x Vcc */ - SSD1329_NOOP, - 0 /* Zero length command terminates table */ -}; - -/* Turn the maxtrix display on (sleep mode off) */ - -static const uint8_t g_sleepoff[] = -{ - SSD1329_SLEEP_OFF, /* Matrix display ON */ - SSD1329_NOOP, -}; - -/* Turn the maxtrix display off (sleep mode on) */ - -static const uint8_t g_sleepon[] = -{ - SSD1329_SLEEP_ON, /* Matrix display OFF */ - SSD1329_NOOP, -}; - -/* Set horizontal increment mode */ - -static const uint8_t g_horzinc[] = -{ - SSD1329_GDDRAM_REMAP, - (SSD1329_COM_SPLIT|SSD1329_COM_REMAP|SSD1329_NIBBLE_REMAP), -}; - -/* The following set a window that covers the entire display */ - -static const uint8_t g_setallcol[] = -{ - SSD1329_SET_COLADDR, - 0, - (RIT_XRES/2)-1 -}; - -static const uint8_t g_setallrow[] = -{ - SSD1329_SET_ROWADDR, - 0, - RIT_YRES-1 -}; - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: rit_configspi - * - * Description: - * Configure the SPI for use with the P14201 - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -static inline void rit_configspi(FAR struct spi_dev_s *spi) -{ -#ifdef CONFIG_P14201_FREQUENCY - ritdbg("Mode: %d Bits: 8 Frequency: %d\n", - CONFIG_P14201_SPIMODE, CONFIG_P14201_FREQUENCY); -#else - ritdbg("Mode: %d Bits: 8\n", CONFIG_P14201_SPIMODE); -#endif - - /* Configure SPI for the P14201. But only if we own the SPI bus. Otherwise, don't - * bother because it might change. - */ - -#ifdef CONFIG_SPI_OWNBUS - SPI_SETMODE(spi, CONFIG_P14201_SPIMODE); - SPI_SETBITS(spi, 8); -#ifdef CONFIG_P14201_FREQUENCY - SPI_SETFREQUENCY(spi, CONFIG_P14201_FREQUENCY) -#endif -#endif -} - -/************************************************************************************** - * Name: rit_select - * - * Description: - * Select the SPI, locking and re-configuring if necessary - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void rit_select(FAR struct spi_dev_s *spi) -{ - /* We own the SPI bus, so just select the chip */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, true); -} -#else -static void rit_select(FAR struct spi_dev_s *spi) -{ - /* Select P14201 chip (locking the SPI bus in case there are multiple - * devices competing for the SPI bus - */ - - SPI_LOCK(spi, true); - SPI_SELECT(spi, SPIDEV_DISPLAY, true); - - /* Now make sure that the SPI bus is configured for the P14201 (it - * might have gotten configured for a different device while unlocked) - */ - - SPI_SETMODE(spi, CONFIG_P14201_SPIMODE); - SPI_SETBITS(spi, 8); -#ifdef CONFIG_P14201_FREQUENCY - SPI_SETFREQUENCY(spi, CONFIG_P14201_FREQUENCY); -#endif -} -#endif - -/************************************************************************************** - * Name: rit_deselect - * - * Description: - * De-select the SPI - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void rit_deselect(FAR struct spi_dev_s *spi) -{ - /* We own the SPI bus, so just de-select the chip */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, false); -} -#else -static void rit_deselect(FAR struct spi_dev_s *spi) -{ - /* De-select P14201 chip and relinquish the SPI bus. */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, false); - SPI_LOCK(spi, false); -} -#endif - -/************************************************************************************** - * Name: rit_sndbytes - * - * Description: - * Send a sequence of command or data bytes to the SSD1329 controller. - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * buffer - A reference to memory containing the command bytes to be sent. - * buflen - The number of command bytes in buffer to be sent - * - * Returned Value: - * None - * - * Assumptions: - * The caller as selected the OLED device. - * - **************************************************************************************/ - -static void rit_sndbytes(FAR struct rit_dev_s *priv, FAR const uint8_t *buffer, - size_t buflen, bool cmd) -{ - FAR struct spi_dev_s *spi = priv->spi; - uint8_t tmp; - - ritdbg("buflen: %d cmd: %s [%02x %02x %02x]\n", - buflen, cmd ? "YES" : "NO", buffer[0], buffer[1], buffer[2] ); - DEBUGASSERT(spi); - - /* Clear/set the D/Cn bit to enable command or data mode */ - - (void)SPI_CMDDATA(spi, SPIDEV_DISPLAY, cmd); - - /* Loop until the entire command/data block is transferred */ - - while (buflen-- > 0) - { - /* Write the next byte to the controller */ - - tmp = *buffer++; - (void)SPI_SEND(spi, tmp); - } -} - -/************************************************************************************** - * Name: rit_sndcmd - * - * Description: - * Send multiple commands from a table of commands. - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * table - A reference to table containing all of the commands to be sent. - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -static void rit_sndcmds(FAR struct rit_dev_s *priv, FAR const uint8_t *table) -{ - int cmdlen; - - /* Table terminates with a zero length command */ - - while ((cmdlen = *table++) != 0) - { - ritdbg("command: %02x cmdlen: %d\n", *table, cmdlen); - rit_sndcmd(priv, table, cmdlen); - table += cmdlen; - } -} - -/************************************************************************************** - * Name: rit_clear - * - * Description: - * This method can be used to clear the entire display. - * - * Input Parameters: - * priv - Reference to private driver structure - * - * Assumptions: - * Caller has selected the OLED section. - * - **************************************************************************************/ - -#ifdef CONFIG_P14201_FRAMEBUFFER -static inline void rit_clear(FAR struct rit_dev_s *priv) -{ - FAR uint8_t *ptr = g_framebuffer; - unsigned int row; - - ritdbg("Clear display\n"); - - /* Initialize the framebuffer */ - - memset(g_framebuffer, (RIT_Y4_BLACK << 4) | RIT_Y4_BLACK, RIT_YRES * RIT_XRES / 2); - - /* Set a window to fill the entire display */ - - rit_sndcmd(priv, g_setallcol, sizeof(g_setallcol)); - rit_sndcmd(priv, g_setallrow, sizeof(g_setallrow)); - rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc)); - - /* Display each row */ - - for(row = 0; row < RIT_YRES; row++) - { - /* Display a horizontal run */ - - rit_snddata(priv, ptr, RIT_XRES / 2); - ptr += RIT_XRES / 2; - } -} -#else -static inline void rit_clear(FAR struct rit_dev_s *priv) -{ - unsigned int row; - - ritdbg("Clear display\n"); - - /* Create a black row */ - - memset(g_runbuffer, (RIT_Y4_BLACK << 4) | RIT_Y4_BLACK, RIT_XRES / 2); - - /* Set a window to fill the entire display */ - - rit_sndcmd(priv, g_setallcol, sizeof(g_setallcol)); - rit_sndcmd(priv, g_setallrow, sizeof(g_setallrow)); - rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc)); - - /* Display each row */ - - for(row = 0; row < RIT_YRES; row++) - { - /* Display a horizontal run */ - - rit_snddata(priv, g_runbuffer, RIT_XRES / 2); - } -} -#endif - -/************************************************************************************** - * Name: rit_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD. - * - * Input Parameters: - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -#ifdef CONFIG_P14201_FRAMEBUFFER -static int rit_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)&g_oleddev; - uint8_t cmd[3]; - uint8_t *run; - int start; - int end; - int aend; - int i; - - ritdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Toss out the special case of the empty run now */ - - if (npixels < 1) - { - return OK; - } - - /* Get the beginning of the line containing run in the framebuffer */ - - run = g_framebuffer + row * RIT_XRES / 2; - - /* Get the starting and ending byte offsets containing the run. - * the run starts at &run[start] and continues through run[end-1]. - * However, the first and final pixels at these locations may - * not be byte aligned. - */ - - start = col >> 1; - aend = (col + npixels) >> 1; - end = (col + npixels + 1) >> 1; - ritdbg("start: %d aend: %d end: %d\n", start, aend, end); - - /* Copy the run into the framebuffer, handling nibble alignment. - * - * CASE 1: First pixel X position is byte aligned - * - * example col=6 npixels = 8 example col=6 npixels=7 - * - * Run: |AB|AB|AB|AB| |AB|AB|AB|AB| - * GDDRAM row: - * Byte | 0| 1| 2| 3| 4| 5| 6| | 0| 1| 2| 3| 4| 5| 6| - * Pixel: |--|--|--|AB|AB|AB|AB| |--|--|--|AB|AB|AB|A-| - * - * start = 3 start = 3 - * aend = 6 aend = 6 - * end = 6 end = 7 - * - */ - - if ((col & 1) == 0) - { - /* Check for the special case of only 1 pixel being blitted */ - - if (npixels > 1) - { - /* Beginning of buffer is properly aligned, from start to aend */ - - memcpy(&run[start], buffer, aend - start); - } - - /* An even number of byte-aligned pixel pairs have been written (where - * zero counts as an even number). If npixels was was odd (including - * npixels == 1), then handle the final, byte aligned pixel. - */ - - if (aend != end) - { - /* The leftmost column is contained in source bits 7:4 and in - * destination bits 7:4 - */ - - run[aend] = (run[aend] & 0x0f) | (buffer[aend - start] & 0xf0); - } - } - - /* CASE 2: First pixel X position is byte aligned - * - * example col=7 npixels = 8 example col=7 npixels=7 - * - * Run: |AB|AB|AB|AB| |AB|AB|AB|AB| - * GDDRAM row: - * Byte | 0| 1| 2| 3| 4| 5| 6| 7| | 0| 1| 2| 3| 4| 5| 6| - * Pixel: |--|--|--|-A|BA|BA|BA|B-| |--|--|--|-A|BA|BA|BA| - * - * start = 3 start = 3 - * aend = 7 aend = 7 - * end = 8 end = 7 - */ - - else - { - uint8_t curr = buffer[0]; - uint8_t last; - - /* Handle the initial unaligned pixel. Source bits 7:4 into - * destination bits 3:0. In the special case of npixel == 1, - * this finished the job. - */ - - run[start] = (run[start] & 0xf0) | (curr >> 4); - - /* Now construct the rest of the bytes in the run (possibly special - * casing the final, partial byte below). - */ - - for (i = start + 1; i < aend; i++) - { - /* bits 3:0 from previous byte to run bits 7:4; - * bits 7:4 of current byte to run bits 3:0 - */ - - last = curr; - curr = buffer[i-start]; - run[i] = (last << 4) | (curr >> 4); - } - - /* An odd number of unaligned pixel have been written (where npixels - * may have been as small as one). If npixels was was even, then handle - * the final, unaligned pixel. - */ - - if (aend != end) - { - /* The leftmost column is contained in source bits 3:0 and in - * destination bits 7:4 - */ - - run[aend] = (run[aend] & 0x0f) | (curr << 4); - } - } - - /* Select the SD1329 controller */ - - rit_select(priv->spi); - - /* Setup a window that describes a run starting at the specified column - * and row, and ending at the column + npixels on the same row. - */ - - cmd[0] = SSD1329_SET_COLADDR; - cmd[1] = start; - cmd[2] = end - 1; - rit_sndcmd(priv, cmd, 3); - - cmd[0] = SSD1329_SET_ROWADDR; - cmd[1] = row; - cmd[2] = row; - rit_sndcmd(priv, cmd, 3); - - /* Write the run to GDDRAM. */ - - rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc)); - rit_snddata(priv, &run[start], end - start); - - /* De-select the SD1329 controller */ - - rit_deselect(priv->spi); - return OK; -} -#else -static int rit_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)&g_oleddev; - uint8_t cmd[3]; - - ritdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - if (npixels > 0) - { - /* Check that the X and Y coordinates are within range */ - - DEBUGASSERT(col < RIT_XRES && (col + npixels) <= RIT_XRES && row < RIT_YRES); - - /* Check that the X coordinates are aligned to 8-bit boundaries - * (this needs to get fixed somehow) - */ - - DEBUGASSERT((col & 1) == 0 && (npixels & 1) == 0); - - /* Select the SD1329 controller */ - - rit_select(priv->spi); - - /* Setup a window that describes a run starting at the specified column - * and row, and ending at the column + npixels on the same row. - */ - - cmd[0] = SSD1329_SET_COLADDR; - cmd[1] = col >> 1; - cmd[2] = ((col + npixels) >> 1) - 1; - rit_sndcmd(priv, cmd, 3); - - cmd[0] = SSD1329_SET_ROWADDR; - cmd[1] = row; - cmd[2] = row; - rit_sndcmd(priv, cmd, 3); - - /* Write the run to GDDRAM. */ - - rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc)); - rit_snddata(priv, buffer, npixels >> 1); - - /* De-select the SD1329 controller */ - - rit_deselect(priv->spi); - } - - return OK; -} -#endif - -/************************************************************************************** - * Name: rit_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -#ifdef CONFIG_P14201_FRAMEBUFFER -static int rit_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ - uint8_t *run; - int start; - int end; - int aend; - int i; - - ritdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Can't read from OLED GDDRAM in SPI mode, but we can read from the framebuffer */ - /* Toss out the special case of the empty run now */ - - if (npixels < 1) - { - return OK; - } - - /* Get the beginning of the line containing run in the framebuffer */ - - run = g_framebuffer + row * RIT_XRES / 2; - - /* Get the starting and ending byte offsets containing the run. - * the run starts at &run[start] and continues through run[end-1]. - * However, the first and final pixels at these locations may - * not be byte aligned (see examples in putrun()). - */ - - start = col >> 1; - aend = (col + npixels) >> 1; - end = (col + npixels + 1) >> 1; - - /* Copy the run into the framebuffer, handling nibble alignment */ - - if ((col & 1) == 0) - { - /* Check for the special case of only 1 pixels being copied */ - - if (npixels > 1) - { - /* Beginning of buffer is properly aligned, from start to aend */ - - memcpy(buffer, &run[start], aend - start + 1); - } - - /* Handle any final pixel (including the special case where npixels == 1). */ - - if (aend != end) - { - /* The leftmost column is contained in source bits 7:4 and in - * destination bits 7:4 - */ - - buffer[aend - start] = run[aend] & 0xf0; - } - } - else - { - uint8_t curr = run[start]; - uint8_t last; - - /* Now construct the rest of the bytes in the run (possibly special - * casing the final, partial byte below). - */ - - for (i = start + 1; i < aend; i++) - { - /* bits 3:0 from previous byte to run bits 7:4; - * bits 7:4 of current byte to run bits 3:0 - */ - - last = curr; - curr = run[i]; - *buffer++ = (last << 4) | (curr >> 4); - } - - /* Handle any final pixel (including the special case where npixels == 1). */ - - if (aend != end) - { - /* The leftmost column is contained in source bits 3:0 and in - * destination bits 7:4 - */ - - *buffer = (curr << 4); - } - } - - return OK; -} -#else -static int rit_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ - /* Can't read from OLED GDDRAM in SPI mode */ - - return -ENOSYS; -} -#endif - -/************************************************************************************** - * Name: rit_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int rit_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", - g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes); - memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: rit_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int rit_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - DEBUGASSERT(pinfo && planeno == 0); - gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp); - memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: rit_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int rit_getpower(FAR struct lcd_dev_s *dev) -{ - FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)dev; - DEBUGASSERT(priv); - - gvdbg("power: %s\n", priv->on ? "ON" : "OFF"); - return priv->on ? CONFIG_LCD_MAXPOWER : 0; -} - -/************************************************************************************** - * Name: rit_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int rit_setpower(struct lcd_dev_s *dev, int power) -{ - struct rit_dev_s *priv = (struct rit_dev_s *)dev; - DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER && priv->spi); - - gvdbg("power: %d\n", power); - - /* Select the SD1329 controller */ - - rit_select(priv->spi); - - /* Only two power settings -- 0: sleep on, 1: sleep off */ - - if (power > 0) - { - /* Re-initialize the SSD1329 controller */ - - rit_sndcmds(priv, g_initcmds); - - /* Take the display out of sleep mode */ - - rit_sndcmd(priv, g_sleepoff, sizeof(g_sleepoff)); - priv->on = true; - } - else - { - /* Put the display into sleep mode */ - - rit_sndcmd(priv, g_sleepon, sizeof(g_sleepon)); - priv->on = false; - } - - /* De-select the SD1329 controller */ - - rit_deselect(priv->spi); - return OK; -} - -/************************************************************************************** - * Name: rit_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int rit_getcontrast(struct lcd_dev_s *dev) -{ - struct rit_dev_s *priv = (struct rit_dev_s *)dev; - - gvdbg("contrast: %d\n", priv->contrast); - return priv->contrast; -} - -/************************************************************************************** - * Name: rit_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int rit_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) -{ - struct rit_dev_s *priv = (struct rit_dev_s *)dev; - uint8_t cmd[3]; - - gvdbg("contrast: %d\n", contrast); - DEBUGASSERT(contrast <= CONFIG_LCD_MAXCONTRAST); - - /* Select the SD1329 controller */ - - rit_select(priv->spi); - - /* Set new contrast */ - - cmd[0] = SSD1329_SET_CONTRAST; - cmd[1] = contrast; - cmd[2] = SSD1329_NOOP; - rit_sndcmd(priv, cmd, 3); - - /* De-select the SD1329 controller */ - - rit_deselect(priv->spi); - priv->contrast = contrast; - return OK; -} - -/************************************************************************************** - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: rit_initialize - * - * Description: - * Initialize the P14201 video hardware. The initial state of the OLED is fully - * initialized, display memory cleared, and the OLED ready to use, but with the power - * setting at 0 (full off == sleep mode). - * - * Input Parameters: - * spi - A reference to the SPI driver instance. - * devno - A value in the range of 0 throuh CONFIG_P14201_NINTERFACES-1. This allows - * support for multiple OLED devices. - * - * Returned Value: - * On success, this function returns a reference to the LCD object for the specified - * OLED. NULL is returned on any failure. - * - **************************************************************************************/ - -FAR struct lcd_dev_s *rit_initialize(FAR struct spi_dev_s *spi, unsigned int devno) -{ - FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)&g_oleddev; - DEBUGASSERT(devno == 0 && spi); - - gvdbg("Initializing devno: %d\n", devno); - - /* Driver state data */ - - priv->spi = spi; - priv->contrast = RIT_CONTRAST; - priv->on = false; - - /* Select the SD1329 controller */ - - rit_configspi(spi); - rit_select(spi); - - /* Clear the display */ - - rit_clear(priv); - - /* Configure (but don't enable) the OLED */ - - rit_sndcmds(priv, g_initcmds); - - /* De-select the SD1329 controller */ - - rit_deselect(spi); - return &priv->dev; -} -#endif /* CONFIG_LCD_P14201 */ diff --git a/nuttx/drivers/lcd/pcf8833.h b/nuttx/drivers/lcd/pcf8833.h deleted file mode 100644 index 36dc65ac3..000000000 --- a/nuttx/drivers/lcd/pcf8833.h +++ /dev/null @@ -1,152 +0,0 @@ -/************************************************************************************** - * drivers/lcd/pcf8833.h - * Definitions for the Phillips PCF8833 LCD controller - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: "Data Sheet, PCF8833 STN RGB 132x132x3 driver," Phillips, 2003 Feb 14. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -#ifndef __DRIVERS_LCD_PCF8833_H -#define __DRIVERS_LCD_PCF8833_H - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ -/* Pixel format codes */ - -#define PCF8833_FMT_8BPS (2) -#define PCF8833_FMT_12BPS (3) -#define PCF8833_FMT_16BPS (5) - -/* LCD Commands */ - -#define PCF8833_NOP 0x00 /* No operation; Data: none */ -#define PCF8833_SWRESET 0x01 /* Software reset ; Data: none */ -#define PCF8833_BSTROFF 0x02 /* Booster voltage off; Data: none */ -#define PCF8833_BSTRON 0x03 /* Booster voltage on; Data: none */ -#define PCF8833_RDDIDIF 0x04 /* Read display identification; Data: none */ -#define PCF8833_RDDST 0x09 /* Read display status; Data: none */ -#define PCF8833_SLEEPIN 0x10 /* Sleep_IN; Data: none */ -#define PCF8833_SLEEPOUT 0x11 /* Sleep_OUT; Data: none */ -#define PCF8833_PTLON 0x12 /* Partial mode on; Data: none */ -#define PCF8833_NORON 0x13 /* Normal Display mode on; Data: none */ -#define PCF8833_INVOFF 0x20 /* Display inversion off; Data: none */ -#define PCF8833_INVON 0x21 /* Display inversion on; Data: none */ -#define PCF8833_DALO 0x22 /* All pixel off; Data: none */ -#define PCF8833_DAL 0x23 /* All pixel on; Data: none */ -#define PCF8833_SETCON 0x25 /* Set contrast; Data: (1) contrast */ -#define PCF8833_DISPOFF 0x28 /* Display off; Data: none */ -#define PCF8833_DISPON 0x29 /* Display on; Data: none */ -#define PCF8833_CASET 0x2a /* Column address set; Data: (1) X start (2) X end */ -#define PCF8833_PASET 0x2b /* Page address set Data: (1) Y start (2) Y end */ -#define PCF8833_RAMWR 0x2c /* Memory write; Data: (1) write data */ -#define PCF8833_RGBSET 0x2d /* Colour set; Data: (1-8) red tones, (9-16) green tones, (17-20) blue tones */ -#define PCF8833_PTLAR 0x30 /* Partial area; Data: (1) start address (2) end address */ -#define PCF8833_VSCRDEF 0x33 /* Vertical scroll definition; Data: (1) top fixed, (2) scrol area, (3) bottom fixed */ -#define PCF8833_TEOFF 0x34 /* Tearing line off; Data: none */ -#define PCF8833_TEON 0x35 /* Tearing line on; Data: (1) don't care */ -#define PCF8833_MADCTL 0x36 /* Memory data access control; Data: (1) access control settings */ -#define PCF8833_SEP 0x37 /* Set Scroll Entry Point; Data: (1) scroll entry point */ -#define PCF8833_IDMOFF 0x38 /* Idle mode off; Data: none */ -#define PCF8833_IDMON 0x39 /* Idle mode on; Data: none */ -#define PCF8833_COLMOD 0x3a /* Interface pixel format; Data: (1) color interface format */ -#define PCF8833_SETVOP 0xb0 /* Set VOP; Data: (1) VOP5-8 (2) VOP0-4 */ -#define PCF8833_BRS 0xb4 /* Bottom Row Swap; Data: none */ -#define PCF8833_TRS 0xb6 /* Top Row Swap; Data: none */ -#define PCF8833_FINV 0xb9 /* Super Frame INVersion; Data: none */ -#define PCF8833_DOR 0xba /* Data ORder; Data: none */ -#define PCF8833_TCDFE 0xbd /* Enable/disable DF temp comp; Data: none */ -#define PCF8833_TCVOPE 0xbf /* Enable or disable VOP temp comp; Data: none */ -#define PCF8833_EC 0xc0 /* Internal or external oscillator; Data: none */ -#define PCF8833_SETMUL 0xc2 /* Set multiplication factor; Data: (1) Multiplication factor */ -#define PCF8833_TCVOPAB 0xc3 /* Set TCVOP slopes A and B; Data: (1) SLB and SLA */ -#define PCF8833_TCVOPCD 0xc4 /* Set TCVOP slopes C and D; Data: (1) SLD and SLC */ -#define PCF8833_TCDF 0xc5 /* Set divider frequency; Data: Divider factor in region (1) A (2) B (3) C (4) D */ -#define PCF8833_DF8COLOR 0xc6 /* Set divider frequency 8-colour mode; Data: (1) DF80-6 */ -#define PCF8833_SETBS 0xc7 /* Set bias system; Data: (1) Bias systems */ -#define PCF8833_RDTEMP 0xc8 /* Temperature read back; Data: none */ -#define PCF8833_NLI 0xc9 /* N-Line Inversion; Data: (1) NLI time slots invervsion */ -#define PCF8833_RDID1 0xda /* Read ID1; Data: none */ -#define PCF8833_RDID2 0xdb /* Read ID2; Data: none */ -#define PCF8833_RDID3 0xdc /* Read ID3; Data: none */ -#define PCF8833_SFD 0xef /* Select factory defaults; Data: none */ -#define PCF8833_ECM 0xf0 /* Enter Calibration mode; Data: (1) Calibration control settings */ -#define PCF8833_OTPSHTIN 0xf1 /* Shift data in OTP shift registers; Data: Any number of bytes */ - -/* Memory data access control (MADCTL) bit definitions */ - -#define MADCTL_RGB (1 << 3) /* Bit 3: BGR */ -#define MADCTL_LAO (1 << 4) /* Bit 4: Line address order bottom to top */ -#define MADCTL_V (1 << 5) /* Bit 5: Vertical RAM write; in Y direction */ -#define MADCTL_MX (1 << 6) /* Bit 6: Mirror X */ -#define MADCTL_MY (1 << 7) /* Bit 7: Mirror Y */ - -/* PCF8833 status register bit definitions */ -/* CMD format: RDDST command followed by four status bytes: */ -/* Byte 1: D31 d30 D29 D28 D27 D26 --- --- */ - -#define PCF8833_ST_RGB (1 << 2) /* Bit 2: D26 - RGB/BGR order */ -#define PCF8833_ST_LINEADDR (1 << 3) /* Bit 3: D27 - Line address order */ -#define PCF8833_ST_ADDRMODE (1 << 4) /* Bit 4: D28 - Vertical/horizontal addressing mode */ -#define PCF8833_ST_XADDR (1 << 5) /* Bit 5: D29 - X address order */ -#define PCF8833_ST_YADDR (1 << 6) /* Bit 6: D30 - Y address order */ -#define PCF8833_ST_BOOSTER (1 << 7) /* Bit 7: D31 - Booster voltage status */ - -/* Byte 2: --- D22 D21 D20 D19 D18 D17 D16 */ - -#define PCF8833_ST_NORMAL (1 << 0) /* Bit 0: D16 - Normal display mode */ -#define PCF8833_ST_SLEEPIN (1 << 1) /* Bit 1: D17 - Sleep in selected */ -#define PCF8833_ST_PARTIAL (1 << 2) /* Bit 2: D18 - Partial mode on */ -#define PCF8833_ST_IDLE (1 << 3) /* Bit 3: D19 - Idle mode selected */ -#define PCF8833_ST_PIXELFMT_SHIFT (4) /* Bits 4-6: D20-D22 - Interface pixel format */ -#define PCF8833_ST_PIXELFMT_MASK (7 << PCF8833_ST_PIXELFMT_SHIFT) -# define PCF8833_ST_PIXELFMT_8BPS (PCF8833_FMT_8BPS << PCF8833_ST_PIXELFMT_SHIFT) -# define PCF8833_ST_PIXELFMT_12BPS (PCF8833_FMT_12BPS << PCF8833_ST_PIXELFMT_SHIFT) -# define PCF8833_ST_PIXELFMT_16BPS (PCF8833_FMT_16BPS << PCF8833_ST_PIXELFMT_SHIFT) - -/* Byte 3: D15 -- D13 D12 D11 D10 D9 --- */ - -#define PCF8833_ST_TEARING (1 << 1) /* Bit 1: D9 - Tearing effect on */ -#define PCF8833_ST_DISPLAYON (1 << 2) /* Bit 2: D10 - Display on */ -#define PCF8833_ST_PIXELSOFF (1 << 3) /* Bit 3: D11 - All pixels off */ -#define PCF8833_ST_PIXELSON (1 << 4) /* Bit 4: D12 - All pixels on */ -#define PCF8833_ST_INV (1 << 5) /* Bit 5: D13 - Display inversion */ -#define PCF8833_ST_VSCROLL (1 << 7) /* Bit 6: D15 - Vertical scroll mode */ - -/* Byte 4: All zero */ - -#endif /* __DRIVERS_LCD_PCF8833_H */ \ No newline at end of file diff --git a/nuttx/drivers/lcd/s1d15g10.h b/nuttx/drivers/lcd/s1d15g10.h deleted file mode 100644 index 9b5f7738f..000000000 --- a/nuttx/drivers/lcd/s1d15g10.h +++ /dev/null @@ -1,141 +0,0 @@ -/************************************************************************************** - * drivers/lcd/s1d15g10.h - * Definitions for the Epson S1D15G0 LCD controller - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: S1D15G0D08B000, Seiko Epson Corportation, 2002. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -#ifndef __DRIVERS_LCD_S1D15G10_H -#define __DRIVERS_LCD_S1D15G10_H - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ - -/* Epson S1D15G10 Command Set */ - -#define S1D15G10_DISON 0xaf /* Display on; Data: none */ -#define S1D15G10_DISOFF 0xae /* Display off; Data: none */ -#define S1D15G10_DISNOR 0xa6 /* Normal display; Data: none */ -#define S1D15G10_DISINV 0xa7 /* Inverse display; Data: none */ -#define S1D15G10_COMSCN 0xbb /* Common scan direction; Data: (1) common scan direction */ -#define S1D15G10_DISCTL 0xca /* Display control; Data: Data: (1) CL div, F1/2 pat, (2) duty, (3) FR inverse (4) dispersion */ -#define S1D15G10_SLPIN 0x95 /* Sleep in; Data: none */ -#define S1D15G10_SLPOUT 0x94 /* Sleep out; Data: none */ -#define S1D15G10_PASET 0x75 /* Page address set; Data: (1) start page, (2) end page */ -#define S1D15G10_CASET 0x15 /* Column address set; Data: (1) start addr, (2) end addr */ -#define S1D15G10_DATCTL 0xbc /* Data scan direction, etc.; Data: (1) inverse, scan dir (2) RGB, (3) gray-scale */ -#define S1D15G10_RGBSET8 0xce /* 256-color position set; Data: (1-8) red tones, (9-16) green tones, (17-20) blue tones */ -#define S1D15G10_RAMWR 0x5c /* Writing to memory; Data: (1) write data */ -#define S1D15G10_RAMRD 0x5d /* Reading from memory; Data: (1) read data */ -#define S1D15G10_PTLIN 0xa8 /* Partial display in; Data: (1) start addr, (2) end addr */ -#define S1D15G10_PTLOUT 0xa9 /* Partial display out; Data: none */ -#define S1D15G10_RMWIN 0xe0 /* Read and modify write; Data: none */ -#define S1D15G10_RMWOUT 0xee /* End; Data: none */ -#define S1D15G10_ASCSET 0xaa /* Area scroll set; Data: (1) top addr, (2) bottom addr, (3) Num blocks, (4) scroll mode */ -#define S1D15G10_SCSTART 0xab /* Scroll start set; Data: (1) start block addr */ -#define S1D15G10_OSCON 0xd1 /* Internal oscillation on; Data: none */ -#define S1D15G10_OSCOFF 0xd2 /* Internal oscillation off; Data: none */ -#define S1D15G10_PWRCTR 0x20 /* Power control; Data: (1) LCD drive power */ -#define S1D15G10_VOLCTR 0x81 /* Electronic volume control; Data: (1) volume value, (2) resistance ratio */ -#define S1D15G10_VOLUP 0xd6 /* Increment electronic control by 1; Data: none */ -#define S1D15G10_VOLDOWN 0xd7 /* Decrement electronic control by 1; Data: none */ -#define S1D15G10_TMPGRD 0x82 /* Temperature gradient set; Data: (1-14) temperature gradient */ -#define S1D15G10_EPCTIN 0xcd /* Control EEPROM; Data: (1) read/write */ -#define S1D15G10_EPCOUT 0xcc /* Cancel EEPROM control; Data: none */ -#define S1D15G10_EPMWR 0xfc /* Write into EEPROM; Data: none */ -#define S1D15G10_EPMRD 0xfd /* Read from EEPROM; Data: none */ -#define S1D15G10_EPSRRD1 0x7c /* Read register 1; Data: none */ -#define S1D15G10_EPSRRD2 0x7d /* Read regiser 2; Data: none */ -#define S1D15G10_NOP 0x25 /* NOP intruction (0x45?); Data: none */ -#define S1D15G10_STREAD 0x20 /* Status read; Data: none */ - -/* Display control (DISCTL) bit definitions */ - -#define DISCTL_PERIOD_SHIFT (0) /* P1: Bits 0-1, F1 and F2 drive-pattern switching period */ -#define DISCTL_PERIOD_MASK (3 << DISCTL_PERIOD_SHIFT) -# define DISCTL_PERIOD_8 (0 << DISCTL_PERIOD_SHIFT) -# define DISCTL_PERIOD_4 (1 << DISCTL_PERIOD_SHIFT) -# define DISCTL_PERIOD_16 (2 << DISCTL_PERIOD_SHIFT) -# define DISCTL_PERIOD_FLD (3 << DISCTL_PERIOD_SHIFT) -#define DISCTL_CLDIV_SHIFT (2) /* P1: Bits 2-4, Clock divider */ -#define DISCTL_CLDIV_MASK (7 << DISCTL_CLDIV_SHIFT) -# define DISCTL_CLDIV_2 (0 << DISCTL_CLDIV_SHIFT) -# define DISCTL_CLDIV_4 (1 << DISCTL_CLDIV_SHIFT) -# define DISCTL_CLDIV_8 (2 << DISCTL_CLDIV_SHIFT) -# define DISCTL_CLDIV_NONE (3 << DISCTL_CLDIV_SHIFT) - -/* Power control (PWRCTR) bit definitions */ - -#define PWCTR_REFVOLTAGE (1 << 0) /* P1: Bit 0, Turn on reference voltage generation circuit. */ -#define PWCTR_REGULATOR (1 << 1) /* P1: Bit 1, Turn on voltage regulator and circuit voltage follower. */ -#define PWCTR_BOOSTER2 (1 << 2) /* P1: Bit 2, Turn on secondary booster/step-down circuit. */ -#define PWCTR_BOOSTER1 (1 << 3) /* P1: Bit 3, Turn on primary booster circuit. */ -#define PWCTR_EXTR (1 << 4) /* P1: Bit 4, Use external resistance to adjust voltage. */ - -/* Data control (DATCTL) bit definitions */ - -#define DATCTL_PGADDR_INV (1 << 0) /* P1: Bit 0, Inverse display of the page address. */ -#define DATCTL_COLADDR_REV (1 << 1) /* P1: Bit 1, Reverse turn of column address. */ -#define DATCTL_ADDR_PGDIR (1 << 2) /* P1: Bit 2, Address-scan direction in page (vs column) direction. */ - -#define DATCTL_BGR (1 << 0) /* P2: Bit0, RGB->BGR */ - -#define DATCTL_8GRAY (1) /* P3: Bits 0-2 = 001, 8 gray-scale */ -#define DATCTL_16GRAY_A (2) /* P3: Bits 0-2 = 010, 16 gray-scale display type A */ -#define DATCTL_16GRAY_B (4) /* P3: Bits 0-2 = 100, 16 gray-scale display type B */ - -/* Status register bit definions (after reset or NOP) */ - -#define S1D15G10_SR_PARTIAL (1 << 0) /* Bit 0: Partial display */ -#define S1D15G10_SR_NORMAL (1 << 1) /* Bit 1: Normal (vs. inverse) display */ -#define S1D15G10_SR_EEPROM (1 << 2) /* Bit 2: EEPROM access */ -#define S1D15G10_SR_DISPON (1 << 3) /* Bit 3: Display on */ -#define S1D15G10_SR_COLSCAN (1 << 4) /* Bit 4: Column (vs. page) scan direction */ -#define S1D15G10_SR_RMW (1 << 5) /* Bit 5: Read modify write */ -#define S1D15G10_SR_SCROLL (3 << 6) /* Bits 6-7: Area scroll mode */ - -/* Status register bit definions (after EPSRRD1) */ - -#define S1D15G10_SR_VOLUME 0x3f /* Bits 0-5: Electronic volume control values */ - -/* Status register bit definions (after EPSRRD2) */ - -#define S1D15G10_SR_RRATIO 0x07 /* Bits 0-2: Built-in resistance ratio */ - -#endif /* __DRIVERS_LCD_S1D15G10_H */ \ No newline at end of file diff --git a/nuttx/drivers/lcd/sd1329.h b/nuttx/drivers/lcd/sd1329.h deleted file mode 100644 index 5d2ad4948..000000000 --- a/nuttx/drivers/lcd/sd1329.h +++ /dev/null @@ -1,527 +0,0 @@ -/**************************************************************************** - * drivers/lcd/sd1329.h - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_LCD_SD1329_H -#define __DRIVERS_LCD_SD1329_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include - -/**************************************************************************** - * Pre-Processor Definitions - ****************************************************************************/ - -/* SD1329 Commands **********************************************************/ -/* Set column Address. - * - * This triple byte command specifies column start address and end address of - * the display data RAM. This command also sets the column address pointer to - * column start address. This pointer is used to define the current read/write - * column address in graphic display data RAM. If horizontal address increment - * mode is enabled by command 0xa0, after finishing read/write one column data, - * it is incremented automatically to the next column address. Whenever the - * column address pointer finishes accessing the end column address, it is - * reset back to start column address and the row address is incremented to the - * next row. - * - * Byte 1: 0x15 - * Byte 2: A[5:0]: Start Address, range: 0x00-0x3f - * Byte 3: B[5:0]: End Address, range: 0x00-0x3f - */ - -#define SSD1329_SET_COLADDR 0x15 - -/* Set Row Address. - * - * This triple byte command specifies row start address and end address of the - * display data RAM. This command also sets the row address pointer to row - * start address. This pointer is used to define the current read/write row - * address in graphic display data RAM. If vertical address increment mode is - * enabled by command 0xa0, after finishing read/write one row data, it is - * incremented automatically to the next row address. Whenever the row address - * pointer finishes accessing the end row address, it is reset back to start - * row address. - * - * Byte 1: 0x75 - * Byte 2: A[6:0]: Start Address, range: 0x00-0x7f - * Byte 3: B[6:0]: End Address, range: 0x00-0x7f - */ - -#define SSD1329_SET_ROWADDR 0x75 - -/* Set Contract Current - * - * This double byte command is to set Contrast Setting of the display. The - * chip has 256 contrast steps from 0x00 to 0xff. The segment output current - * increases linearly with the increase of contrast step. - * - * Byte 1: 0x81 - * Byte 2: A[7:0]: Contrast Value, range: 0-255 - */ - -#define SSD1329_SET_CONTRAST 0x81 - -/* Set Second Pre-Charge Speed - * - * This command is used to set the speed of second pre-charge in phase 3. - * This speed can be doubled to achieve faster pre-charging through setting - * 0x82 A[0]. - * - * Byte 1: 0x82 - * Byte 2: A[7:1]: Second Pre-charge Speed - * A[0] = 1, Enable doubling the Second Pre-charge speed - */ - -#define SSD1329_PRECHRG2_SPEED 0x82 -# define SSD1329_PRECHRG2_DBL 0x01 - -/* Set Master Icon Control - * - * This double command is used to set the ON / OFF conditions of internal - * charge pump, icon circuits and overall icon status. - * - * Byte 1: 0x90 - * Byte 2: Icon control (OR of bits 0-1,4-5) - */ - -#define SSD1329_ICON_CONTROL 0x90 -# define SSD1329_ICON_NORMAL 0x00 /* A[1:0]1=00: Icon RESET to normal display */ -# define SSD1329_ICON_ALLON 0x01 /* A[1:0]1=01: Icon All ON */ -# define SSD1329_ICON_ALLOFF 0x02 /* A[1:0]=10: Icon All OFF */ -# define SSD1329_ICON_DISABLE 0x00 /* A[4]=0: Disable Icon display */ -# define SSD1329_ICON_ENABLE 0x10 /* A[4]=1: Enable Icon display */ -# define SSD1329_VICON_DISABLE 0x00 /* A[5]=0: Disable VICON charge pump circuit */ -# define SSD1329_VICON_ENABLE 0x20 /* A[5]=1: Enable VICON charge pump circuit */ - -/* Set Icon Current Range - * - * This double byte command is used to set one fix current range for all icons - * between the range of 0uA and 127.5uA. The uniformity improves as the icon - * current range increases. - * - * Byte 1: 0x91 - * Byte 2: A[7:0]: Max icon current: - * 00 = 0.0 uA - * 01 = 0.5 uA - * ... - * ff = 127.5 uA - */ - -#define SSD1329_ICON_CURRRNG 0x91 - -/* Set Individual Icon Current - * - * This multiple byte command is used to fine tune the current for each of the - * 64 icons. Command 0x92 followed by 64 single byte data. These 64 byte data - * have to be entered in order to make this command function. Below is the - * formula for calculating the icon current. - * - * Icon Current = Single byte value / 127 x Maximum icon current set with command 0x91 - * - * Byte 1: 0x92 - * Byte 2-65: An[6:0]: icon current for ICSn, range: 0x00-0x7f - * Icon Current of ICSn = An[6:0]/127) x max icon current - */ - -#define SSD1329_ICON_CURRENT 0x92 - -/* Set Individual Icon ON / OFF Register - * - * This double byte command is used to select one of the 64 icons and choose the - * ON, OFF or blinking condition of the selected icon. - * - * Byte 1: 0x93 - * Byte 2: A[5:0]: Select one of the 64 icons from ICS0 ~ ICS63 - * A[7:6]: OFF/ON/BLINK - */ - -#define SSD1329_ICON_SELECT 0x93 -# define SSD1329_ICON_OFF 0x00 -# define SSD1329_ICON_ON 0x40 -# define SSD1329_ICON_BLINK 0xc0 - -/* Set Icon ON / OFF Registers - * - * This double byte command is used to set the ON / OFF status of all 64 icons. - * - * Byte 1: 0x94 - * Byte 2: A[7:6]: OFF/ON/BLINK (Same as 0x93) - */ - -#define SSD1329_ICON_ALL 0x94 - -/* Set Icon Blinking Cycle - * - * This double byte command is used to set icon oscillator frequency and - * blinking cycle selected with above command 0x93. - * - * Byte 1: 0x95 - * Byte 2: - * - A[2:0]:Icon Blinking cycle - * - A[5:4]:Icon oscillation frequency - */ - -#define SSD1329_ICON_BLINKING 0x95 -# define SSD1329_ICON_BLINK_0p25S 0x00 /* 0.25 sec */ -# define SSD1329_ICON_BLINK_0p50S 0x01 /* 0.50 sec */ -# define SSD1329_ICON_BLINK_0p75S 0x02 /* 0.75 sec */ -# define SSD1329_ICON_BLINK_0p100S 0x03 /* 1.00 sec */ -# define SSD1329_ICON_BLINK_0p125S 0x04 /* 1.25 sec */ -# define SSD1329_ICON_BLINK_0p150S 0x05 /* 1.50 sec */ -# define SSD1329_ICON_BLINK_0p175S 0x06 /* 1.75 sec */ -# define SSD1329_ICON_BLINK_0p200S 0x07 /* 2.00 sec */ -# define SSD1329_ICON_BLINK_61KHZ 0x00 /* 61 KHz */ -# define SSD1329_ICON_BLINK_64KHZ 0x10 /* 64 KHz */ -# define SSD1329_ICON_BLINK_68KHZ 0x20 /* 68 KHz */ -# define SSD1329_ICON_BLINK_73KHZ 0x30 /* 73 KHz */ - -/* Set Icon Duty - * - * This double byte command is used to set the icon frame frequency and icon AC - * drive duty ratio. - * - * Byte 1: 0x96 - * Byte 2: - * - A[2:0]: AC Drive - * - A[7:4]: con frame frequency - */ - -#define SSD1329_ICON_ACDRIVE 0x96 -# define SSD1329_ICON_DUTY_DC 0x00 -# define SSD1329_ICON_DUTY_63_64 0x01 -# define SSD1329_ICON_DUTY_62_64 0x02 -# define SSD1329_ICON_DUTY_61_64 0x03 -# define SSD1329_ICON_DUTY_60_64 0x04 -# define SSD1329_ICON_DUTY_59_64 0x05 -# define SSD1329_ICON_DUTY_58_64 0x06 -# define SSD1329_ICON_DUTY_57_64 0x07 - -/* Set Re-map - * - * This double command has multiple configurations and each bit setting is - * described as follows: - * - * Column Address Remapping (A[0]) - * This bit is made for increase the flexibility layout of segment signals in - * OLED module with segment arranged from left to right (when A[0] is set to 0) - * or from right to left (when A[0] is set to 1). - * - * Nibble Remapping (A[1]) - * When A[1] is set to 1, the two nibbles of the data bus for RAM access are - * re-mapped, such that (D7, D6, D5, D4, D3, D2, D1, D0) acts like (D3, D2, D1, - * D0, D7, D6, D5, D4) If this feature works together with Column Address - * Re-map, it would produce an effect of flipping the outputs from SEG0-127 to - * SEG127-SEG0. - * - * Address increment mode (A[2]) - * When A[2] is set to 0, the driver is set as horizontal address incremen - * mode. After the display RAM is read/written, the column address pointer is - * increased automatically by 1. If the column address pointer reaches column - * end address, the column address pointer is reset to column start address and - * row address pointer is increased by 1. - * - * When A[2] is set to 1, the driver is set to vertical address increment mode. - * After the display RAM is read/written, the row address pointer is increased - * automatically by 1. If the row address pointer reaches the row end address, - * the row address pointer is reset to row start address and column address - * pointer is increased by 1. - * - * COM Remapping (A[4]) - * This bit defines the scanning direction of the common for flexible layout - * of common signals in OLED module either from up to down (when A[4] is set to - * 0) or from bottom to up (when A[4] is set to 1). - * - * Splitting of Odd / Even COM Signals (A[6]) - * This bit is made to match the COM layout connection on the panel. When A[6] - * is set to 0, no splitting odd / even of the COM signal is performed. When - * A[6] is set to 1, splitting odd / even of the COM signal is performed, - * output pin assignment sequence is shown as below (for 128MUX ratio): - * - * Byte 1: 0xa0 - * Byte 2: A[7:0] - */ - -#define SSD1329_GDDRAM_REMAP 0xa0 -# define SSD1329_COLADDR_REMAP 0x01 /* A[0]: Enable column re-map */ -# define SSD1329_NIBBLE_REMAP 0x02 /* A[1]: Enable nibble re-map */ -# define SSD1329_VADDR_INCR 0x04 /* A[1]: Enable vertical address increment */ -# define SSD1329_COM_REMAP 0x10 /* A[4]: Enable COM re-map */ -# define SSD1329_COM_SPLIT 0x40 /* A[6]: Enable COM slip even/odd */ - -/* Set Display Start Line - * - * This double byte command is to set Display Start Line register for - * determining the starting address of display RAM to be displayed by selecting - * a value from 0 to 127. - * - * Byte 1: 0xa1 - * Byte 2: A[6:0]: Vertical scroll by setting the starting address of - * display RAM from 0-127 - */ - -#define SSD1329_VERT_START 0xa1 - -/* Set Display Offset - * - * This double byte command specifies the mapping of display start line (it is - * assumed that COM0 is the display start line, display start line register - * equals to 0) to one of COM0-COM127. - * - * Byte 1: 0xa2 - * Byte 2: A[6:0]: Set vertical offset by COM from 0-127 - */ - -#define SSD1329_VERT_OFFSET 0xa2 - -/* Set Display Mode - Normal, all on, all off, inverse - * - * These are single byte commands and are used to set display status to Normal - * Display, Entire Display ON, Entire Display OFF or Inverse Display. - * - * Normal Display (0xa4) - * Reset the “Entire Display ON, Entire Display OFF or Inverse Display” effects - * and turn the data to ON at the corresponding gray level. - * - * Set Entire Display ON (0xa5) - * Force the entire display to be at gray scale level GS15, regardless of the - * contents of the display data RAM. - * - * Set Entire Display OFF (0xa6) - * Force the entire display to be at gray scale level GS0, regardless of the - * contents of the display data RAM. - * - * Inverse Display (0xa7) - * The gray scale level of display data are swapped such that “GS0” <-> “GS15”, - * “GS1” <-> “GS14”, etc. - * - * Byte 1: Display mode command - */ - -#define SSD1329_DISP_NORMAL 0xa4 -#define SSD1329_DISP_OFF 0xa5 -#define SSD1329_DISP_ON 0xa6 -#define SSD1329_DISP_INVERT 0xa7 - -/* Set MUX Ratio - * - * This double byte command sets multiplex ratio (MUX ratio) from 16MUX to - * 128MUX. In POR, multiplex ratio is 128MUX. - * - * Byte 1: 0xa8 - * Byte 2: A[6:0] 15-127 representing 16-128 MUX - */ - -#define SSD1329_MUX_RATIO 0xa8 - -/* Set Sleep mode ON / OFF - * - * These single byte commands are used to turn the matrix display on the OLED - * panel display either ON or OFF. When the sleep mode is set to ON (0xae), the - * display is OFF, the segment and common output are in high impedance state - * and circuits will be turned OFF. When the sleep mode is set to OFF (0xaf), - * the display is ON. - * - * Byte 1: sleep mode command - */ - -#define SSD1329_SLEEP_ON 0xae -#define SSD1329_SLEEP_OFF 0xaf - -/* Set Phase Length - * - * In the second byte of this double command, lower nibble and higher nibble is - * defined separately. The lower nibble adjusts the phase length of Reset (phase - * 1). The higher nibble is used to select the phase length of first pre-charge - * phase (phase 2). The phase length is ranged from 1 to 16 DCLK's. RESET for - * A[3:0] is set to 3 which means 4 DCLK’s selected for Reset phase. POR for - * A[7:4] is set to 5 which means 6 DCLK’s is selected for first pre-charge - * phase. Please refer to Table 9-1 for detail breakdown levels of each step. - * - * Byte 1: 0xb1 - * Byte 2: A[3:0]: Phase 1 period of 1~16 DCLK’s - * A[7:4]: Phase 2 period of 1~16 DCLK’s - */ - -#define SSD1329_PHASE_LENGTH 0xb1 - -/* Set Frame Frequency - * - * This double byte command is used to set the number of DCLK’s per row between - * the range of 0x14 and 0x7f. Then the Frame frequency of the matrix display - * is equal to DCLK frequency / A[6:0]. - * - * Byte 1: 0xb2 - * Byte 2: A[6:0]:Total number of DCLK’s per row. Ranging from - * 0x14 to 0x4e DCLK’s. frame Frequency = DCLK freq /A[6:0]. - */ - -#define SSD1329_FRAME_FREQ 0xb2 - -/* Set Front Clock Divider / Oscillator Frequency - * - * This double command is used to set the frequency of the internal display - * clocks, DCLK's. It is defined by dividing the oscillator frequency by the - * divide ratio (Value from 1 to 16). Frame frequency is determined by divide - * ratio, number of display clocks per row, MUX ratio and oscillator frequency. - * The lower nibble of the second byte is used to select the oscillator - * frequency. Please refer to Table 9-1 for detail breakdown levels of each - * step. - * - * Byte 1: 0xb3 - * Byte 2: A[3:0]: Define divide ratio (D) of display clock (DCLK) - * Divide ratio=A[3:0]+1 - * A[7:4] : Set the Oscillator Frequency, FOSC. Range:0-15 - */ - -#define SSD1329_DCLK_DIV 0xb3 - -/* Set Default Gray Scale Table - * - * This single byte command is used to set the gray scale table to initial - * default setting. - * - * Byte 1: 0xb7 - */ - -#define SSD1329_GSCALE_TABLE 0xb7 - -/* Look Up Table for Gray Scale Pulse width - * - * This command is used to set each individual gray scale level for the display. - * Except gray scale level GS0 that has no pre-charge and current drive, each - * gray scale level is programmed in the length of current drive stage pulse - * width with unit of DCLK. The longer the length of the pulse width, the - * brighter the OLED pixel when it’s turned ON. - * - * The setting of gray scale table entry can perform gamma correction on OLED - * panel display. Normally, it is desired that the brightness response of the - * panel is linearly proportional to the image data value in display data RAM. - * However, the OLED panel is somehow responded in non-linear way. Appropriate - * gray scale table setting like example below can compensate this effect. - * - * Byte 1: 0xb8 - * Bytes 2-16: An[5:0], value for GSn level Pulse width - */ - -#define SSD1329_GSCALE_LOOKUP 0xb8 - -/* Set Second Pre-charge Period - * - * This double byte command is used to set the phase 3 second pre-charge period. - * The period of phase 3 can be programmed by command 0xbb and it is ranged from - * 0 to 15 DCLK's. - * - * Byte 1: 0xbb - * Byte 2: 0-15 DCLKs - */ - -#define SSD1329_PRECHRG2_PERIOD 0xbb - -/* Set First Precharge voltage, VP - * - * This double byte command is used to set phase 2 first pre-charge voltage - * level. It can be programmed to set the first pre-charge voltage reference to - * VCC or VCOMH. - * - * Byte 1: 0xbc - * Byte 2: A[5] == 0, Pre-charge voltage is (0.30 + A[4:0]) * Vcc - * A{5] == 1, 1.00 x VCC or connect to VCOMH if VCC > VCOMH - */ - -#define SSD1329_PRECHRG1_VOLT 0xbc - -/* Set VCOMH - * - * This double byte command sets the high voltage level of common pins, VCOMH. - * The level of VCOMH is programmed with reference to VCC. - * - * Byte 1: 0xbe - * Byte 2: (0.51 + A[5:0]) * Vcc - */ - -#define SSD1329_COM_HIGH 0xbe - -/* NOOP - * - * This is a no operation command. - * - * Byte 1: 0xe3 - */ - -#define SSD1329_NOOP 0xe3 - -/* Set Command Lock - * - * This command is used to lock the MCU from accepting any command. - * - * Byte 1: 0xfd - * Byte 2: 0x12 | A[2] - * A[2] == 1, Enable locking the MCU from entering command - */ - -#define SSD1329_CMD_LOCK 0xfd -# define SSD1329_LOCK_ON 0x13 -# define SSD1329_LOCK_OFF 0x12 - -/* SD1329 Status ************************************************************/ - -#define SDD1329_STATUS_ON 0x00 /* D[6]=0: indicates the display is ON */ -#define SDD1329_STATUS_OFF 0x40 /* D[6]=1: indicates the display is OFF */ - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#if defined(__cplusplus) -} -#endif -#endif /* __DRIVERS_LCD_SD1329_H */ diff --git a/nuttx/drivers/lcd/skeleton.c b/nuttx/drivers/lcd/skeleton.c deleted file mode 100644 index 83aa92018..000000000 --- a/nuttx/drivers/lcd/skeleton.c +++ /dev/null @@ -1,401 +0,0 @@ -/************************************************************************************** - * drivers/lcd/skeleton.c - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "up_arch.h" - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ - -/* Configuration **********************************************************************/ -/* Verify that all configuration requirements have been met */ - -/* Debug ******************************************************************************/ -/* Define the following to enable register-level debug output */ - -#undef CONFIG_LCD_SKELDEBUG - -/* Verbose debug must also be enabled */ - -#ifndef CONFIG_DEBUG -# undef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_GRAPHICS -#endif - -#ifndef CONFIG_DEBUG_VERBOSE -# undef CONFIG_LCD_SKELDEBUG -#endif - -/* Color Properties *******************************************************************/ - -/* Display Resolution */ - -#define SKEL_XRES 320 -#define SKEL_YRES 240 - -/* Color depth and format */ - -#define SKEL_BPP 16 -#define SKEL_COLORFMT FB_FMT_RGB16_565 - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_LCD_SKELDEBUG -# define skeldbg(format, arg...) vdbg(format, ##arg) -#else -# define skeldbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct skel_dev_s -{ - /* Publically visible device structure */ - - struct lcd_dev_s dev; - - /* Private LCD-specific information follows */ -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ - -/* LCD Data Transfer Methods */ - -static int skel_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels); -static int skel_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int skel_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int skel_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int skel_getpower(struct lcd_dev_s *dev); -static int skel_setpower(struct lcd_dev_s *dev, int power); -static int skel_getcontrast(struct lcd_dev_s *dev); -static int skel_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - -static uint16_t g_runbuffer[SKEL_XRES]; - -/* This structure describes the overall LCD video controller */ - -static const struct fb_videoinfo_s g_videoinfo = -{ - .fmt = SKEL_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - .xres = SKEL_XRES, /* Horizontal resolution in pixel columns */ - .yres = SKEL_YRES, /* Vertical resolution in pixel rows */ - .nplanes = 1, /* Number of color planes supported */ -}; - -/* This is the standard, NuttX Plane information object */ - -static const struct lcd_planeinfo_s g_planeinfo = -{ - .putrun = skel_putrun, /* Put a run into LCD memory */ - .getrun = skel_getrun, /* Get a run from LCD memory */ - .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */ - .bpp = SKEL_BPP, /* Bits-per-pixel */ -}; - -/* This is the standard, NuttX LCD driver object */ - -static struct skel_dev_s g_lcddev = -{ - .dev = - { - /* LCD Configuration */ - - .getvideoinfo = skel_getvideoinfo, - .getplaneinfo = skel_getplaneinfo, - - /* LCD RGB Mapping -- Not supported */ - /* Cursor Controls -- Not supported */ - - /* LCD Specific Controls */ - - .getpower = skel_getpower, - .setpower = skel_setpower, - .getcontrast = skel_getcontrast, - .setcontrast = skel_setcontrast, - }, -}; - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: skel_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD: - * - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int skel_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - /* Buffer must be provided and aligned to a 16-bit address boundary */ - - gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); - - /* Set up to write the run. */ - - /* Write the run to GRAM. */ -#warning "Missing logic" - return OK; -} - -/************************************************************************************** - * Name: skel_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int skel_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ - /* Buffer must be provided and aligned to a 16-bit address boundary */ - - gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); - -#warning "Missing logic" - return -ENOSYS; -} - -/************************************************************************************** - * Name: skel_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int skel_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", - g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes); - memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: skel_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int skel_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - DEBUGASSERT(dev && pinfo && planeno == 0); - gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp); - memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: skel_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int skel_getpower(struct lcd_dev_s *dev) -{ - struct skel_dev_s *priv = (struct skel_dev_s *)dev; - gvdbg("power: %d\n", 0); -#warning "Missing logic" - return 0; -} - -/************************************************************************************** - * Name: skel_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int skel_setpower(struct lcd_dev_s *dev, int power) -{ - struct skel_dev_s *priv = (struct skel_dev_s *)dev; - - gvdbg("power: %d\n", power); - DEBUGASSERT(power <= CONFIG_LCD_MAXPOWER); - - /* Set new power level */ -#warning "Missing logic" - - return OK; -} - -/************************************************************************************** - * Name: skel_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int skel_getcontrast(struct lcd_dev_s *dev) -{ - gvdbg("Not implemented\n"); -#warning "Missing logic" - return -ENOSYS; -} - -/************************************************************************************** - * Name: skel_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int skel_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) -{ - gvdbg("contrast: %d\n", contrast); -#warning "Missing logic" - return -ENOSYS; -} - -/************************************************************************************** - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: up_oledinitialize - * - * Description: - * Initialize the LCD video hardware. The initial state of the LCD is fully - * initialized, display memory cleared, and the LCD ready to use, but with the power - * setting at 0 (full off). - * - **************************************************************************************/ - -FAR struct lcd_dev_s *up_oledinitialize(FAR struct spi_dev_s *spi) -{ - gvdbg("Initializing\n"); - - /* Configure GPIO pins */ -#warning "Missing logic" - - /* Enable clocking */ -#warning "Missing logic" - - /* Configure and enable LCD */ - #warning "Missing logic" - - return &g_lcddev.dev; -} diff --git a/nuttx/drivers/lcd/ssd1289.c b/nuttx/drivers/lcd/ssd1289.c deleted file mode 100644 index d78688be5..000000000 --- a/nuttx/drivers/lcd/ssd1289.c +++ /dev/null @@ -1,1380 +0,0 @@ -/************************************************************************************** - * drivers/lcd/ssd1289.c - * - * Generic LCD driver for LCDs based on the Solomon Systech SSD1289 LCD controller. - * Think of this as a template for an LCD driver that you will proably ahve to - * customize for any particular LCD hardware. - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * - * References: SSD1289, Rev 1.3, Apr 2007, Solomon Systech Limited - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ssd1289.h" - -#ifdef CONFIG_LCD_SSD1289 - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ -/* Configuration **********************************************************************/ - -/* Check contrast selection */ - -#if !defined(CONFIG_LCD_MAXCONTRAST) -# define CONFIG_LCD_MAXCONTRAST 1 -#endif - -/* Check power setting */ - -#if !defined(CONFIG_LCD_MAXPOWER) || CONFIG_LCD_MAXPOWER < 1 -# define CONFIG_LCD_MAXPOWER 1 -#endif - -#if CONFIG_LCD_MAXPOWER > 255 -# error "CONFIG_LCD_MAXPOWER must be less than 256 to fit in uint8_t" -#endif - -/* Check orientation */ - -#if defined(CONFIG_LCD_PORTRAIT) -# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) || defined(CONFIG_LCD_RPORTRAIT) -# error "Cannot define both portrait and any other orientations" -# endif -#elif defined(CONFIG_LCD_RPORTRAIT) -# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -# error "Cannot define both rportrait and any other orientations" -# endif -#elif defined(CONFIG_LCD_LANDSCAPE) -# ifdef CONFIG_LCD_RLANDSCAPE -# error "Cannot define both landscape and any other orientations" -# endif -#elif !defined(CONFIG_LCD_RLANDSCAPE) -# define CONFIG_LCD_LANDSCAPE 1 -#endif - -/* Define CONFIG_DEBUG_LCD to enable detailed LCD debug output. Verbose debug must - * also be enabled. - */ - -#ifndef CONFIG_DEBUG -# undef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_GRAPHICS -# undef CONFIG_DEBUG_LCD -#endif - -#ifndef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_LCD -#endif - -/* Display/Color Properties ***********************************************************/ -/* Display Resolution */ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -# define SSD1289_XRES 320 -# define SSD1289_YRES 240 -#else -# define SSD1289_XRES 240 -# define SSD1289_YRES 320 -#endif - -/* Color depth and format */ - -#define SSD1289_BPP 16 -#define SSD1289_COLORFMT FB_FMT_RGB16_565 - -/* LCD Profiles ***********************************************************************/ -/* Many details of the controller initialization must, unfortunately, vary from LCD to - * LCD. I have looked at the spec and at three different drivers for LCDs that have - * SSD1289 controllers. I have tried to summarize these differences as "LCD profiles" - * - * Most of the differences between LCDs are nothing more than a few minor bit - * settings. The most significant difference betwen LCD drivers in is the - * manner in which the LCD is powered up and in how the power controls are set. - * My suggestion is that if you have working LCD initialization code, you should - * simply replace the code in ssd1289_hwinitialize with your working code. - */ - -#if defined (CONFIG_SSD1289_PROFILE2) -# undef SSD1289_USE_SIMPLE_INIT - - /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */ - -# define PWRCTRL1_SETTING \ - (SSD1289_PWRCTRL1_AP_SMMED | SSD1289_PWRCTRL1_DC_FLINEx24 | \ - SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FLINEx24) - - /* PWRCTRL2: 5.1v */ - -# define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p1V - - /* PWRCTRL3: x 2.165 - * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec. - */ - -# define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p165 - - /* PWRCTRL4: VDV=9 + VCOMG */ - -# define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(9) | SSD1289_PWRCTRL4_VCOMG) - - /* PWRCTRL5: VCM=56 + NOTP */ - -# define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(56) | SSD1289_PWRCTRL5_NOTP) - -#elif defined (CONFIG_SSD1289_PROFILE3) -# undef SSD1289_USE_SIMPLE_INIT - - /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */ - -# define PWRCTRL1_SETTING \ - (SSD1289_PWRCTRL1_AP_SMMED | SSD1289_PWRCTRL1_DC_FLINEx24 | \ - SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FLINEx24) - - /* PWRCTRL2: 5.1v */ - -# define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p1V - - /* PWRCTRL3: x 2.165 - * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec. - */ - -# define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p165 - - /* PWRCTRL4: VDV=9 + VCOMG */ - -# define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(9) | SSD1289_PWRCTRL4_VCOMG) - - /* PWRCTRL5: VCM=56 + NOTP */ - -# define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(56) | SSD1289_PWRCTRL5_NOTP) - -#else /* if defined (CONFIG_SSD1289_PROFILE1) */ -# undef SSD1289_USE_SIMPLE_INIT -# define SSD1289_USE_SIMPLE_INIT 1 - - /* PWRCTRL1: AP=medium-to-large, DC=Fosc/4, BT=+5/-4, DCT=Fosc/4 */ - -# define PWRCTRL1_SETTING \ - (SSD1289_PWRCTRL1_AP_MEDLG | SSD1289_PWRCTRL1_DC_FOSd4 | \ - SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FOSd4) - - /* PWRCTRL2: 5.3v */ - -# define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p3V - - /* PWRCTRL3: x 2.570 - * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec. - */ - -# define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p570 - - /* PWRCTRL4: VDV=12 + VCOMG */ - -# define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(12) | SSD1289_PWRCTRL4_VCOMG) - - /* PWRCTRL5: VCM=60 + NOTP */ - -# define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(60) | SSD1289_PWRCTRL5_NOTP) - -#endif - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_DEBUG_LCD -# define lcddbg dbg -# define lcdvdbg vdbg -#else -# define lcddbg(x...) -# define lcdvdbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct ssd1289_dev_s -{ - /* Publically visible device structure */ - - struct lcd_dev_s dev; - - /* Private LCD-specific information follows */ - - FAR struct ssd1289_lcd_s *lcd; /* The contained platform-specific, LCD interface */ - uint8_t power; /* Current power setting */ - - /* These fields simplify and reduce debug output */ - -#ifdef CONFIG_DEBUG_LCD - bool put; /* Last raster operation was a putrun */ - fb_coord_t firstrow; /* First row of the run */ - fb_coord_t lastrow; /* Last row of the run */ - fb_coord_t col; /* Column of the run */ - size_t npixels; /* Length of the run */ -#endif - - /* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - - uint16_t runbuffer[SSD1289_XRES]; -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ -/* Low Level LCD access */ - -static void ssd1289_putreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr, - uint16_t regval); -#ifndef CONFIG_LCD_NOGETRUN -static uint16_t ssd1289_readreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr); -#endif -static inline void ssd1289_gramwrite(FAR struct ssd1289_lcd_s *lcd, uint16_t rgbcolor); -#ifndef CONFIG_LCD_NOGETRUN -static inline void ssd1289_readsetup(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum); -static inline uint16_t ssd1289_gramread(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum); -#endif -static void ssd1289_setcursor(FAR struct ssd1289_lcd_s *lcd, uint16_t column, - uint16_t row); - -/* LCD Data Transfer Methods */ - -#if 0 /* Sometimes useful */ -static void ssd1289_dumprun(FAR const char *msg, FAR uint16_t *run, size_t npixels); -#else -# define ssd1289_dumprun(m,r,n) -#endif - -#ifdef CONFIG_DEBUG_LCD -static void ssd1289_showrun(FAR struct ssd1289_dev_s *priv, fb_coord_t row, - fb_coord_t col, size_t npixels, bool put); -#else -# define ssd1289_showrun(p,r,c,n,b) -#endif - -static int ssd1289_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels); -static int ssd1289_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int ssd1289_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int ssd1289_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int ssd1289_getpower(FAR struct lcd_dev_s *dev); -static int ssd1289_setpower(FAR struct lcd_dev_s *dev, int power); -static int ssd1289_getcontrast(FAR struct lcd_dev_s *dev); -static int ssd1289_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast); - -/* Initialization */ - -static inline int ssd1289_hwinitialize(FAR struct ssd1289_dev_s *priv); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This driver can support only a signal SSD1289 device. This is due to an - * unfortunate decision made whent he getrun and putrun methods were designed. The - * following is the single SSD1289 driver state instance: - */ - -static struct ssd1289_dev_s g_lcddev; - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ssd1289_putreg(lcd, - * - * Description: - * Write to an LCD register - * - **************************************************************************************/ - -static void ssd1289_putreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr, uint16_t regval) -{ - /* Set the index register to the register address and write the register contents */ - - lcd->index(lcd, regaddr); - lcd->write(lcd, regval); -} - -/************************************************************************************** - * Name: ssd1289_readreg - * - * Description: - * Read from an LCD register - * - **************************************************************************************/ - -#ifndef CONFIG_LCD_NOGETRUN -static uint16_t ssd1289_readreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr) -{ - /* Set the index register to the register address and read the register contents */ - - lcd->index(lcd, regaddr); - return lcd->read(lcd); -} -#endif - -/************************************************************************************** - * Name: ssd1289_gramselect - * - * Description: - * Setup to read or write multiple pixels to the GRAM memory - * - **************************************************************************************/ - -static inline void ssd1289_gramselect(FAR struct ssd1289_lcd_s *lcd) -{ - lcd->index(lcd, SSD1289_DATA); -} - -/************************************************************************************** - * Name: ssd1289_gramwrite - * - * Description: - * Setup to read or write multiple pixels to the GRAM memory - * - **************************************************************************************/ - -static inline void ssd1289_gramwrite(FAR struct ssd1289_lcd_s *lcd, uint16_t data) -{ - lcd->write(lcd, data); -} - -/************************************************************************************** - * Name: ssd1289_readsetup - * - * Description: - * Prime the operation by reading one pixel from the GRAM memory if necessary for - * this LCD type. When reading 16-bit gram data, there may be some shifts in the - * returned data: - * - * - ILI932x: Discard first dummy read; no shift in the return data - * - **************************************************************************************/ - -#ifndef CONFIG_LCD_NOGETRUN -static inline void ssd1289_readsetup(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum) -{ - /* Read-ahead one pixel */ - - *accum = lcd->read(lcd); -} -#endif - -/************************************************************************************** - * Name: ssd1289_gramread - * - * Description: - * Read one correctly aligned pixel from the GRAM memory. Possibly shifting the - * data and possibly swapping red and green components. - * - * - ILI932x: Unknown -- assuming colors are in the color order - * - **************************************************************************************/ - -#ifndef CONFIG_LCD_NOGETRUN -static inline uint16_t ssd1289_gramread(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum) -{ - /* Read the value (GRAM register already selected) */ - - return lcd->read(lcd); -} -#endif - -/************************************************************************************** - * Name: ssd1289_setcursor - * - * Description: - * Set the cursor position. In landscape mode, the "column" is actually the physical - * Y position and the "row" is the physical X position. - * - **************************************************************************************/ - -static void ssd1289_setcursor(FAR struct ssd1289_lcd_s *lcd, uint16_t column, uint16_t row) -{ -#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT) - ssd1289_putreg(lcd, SSD1289_XADDR, column); /* 0-239 */ - ssd1289_putreg(lcd, SSD1289_YADDR, row); /* 0-319 */ -#elif defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) - ssd1289_putreg(lcd, SSD1289_XADDR, row); /* 0-239 */ - ssd1289_putreg(lcd, SSD1289_YADDR, column); /* 0-319 */ -#endif -} - -/************************************************************************************** - * Name: ssd1289_dumprun - * - * Description: - * Dump the contexts of the run buffer: - * - * run - The buffer in containing the run read to be dumped - * npixels - The number of pixels to dump - * - **************************************************************************************/ - -#if 0 /* Sometimes useful */ -static void ssd1289_dumprun(FAR const char *msg, FAR uint16_t *run, size_t npixels) -{ - int i, j; - - syslog("\n%s:\n", msg); - for (i = 0; i < npixels; i += 16) - { - up_putc(' '); - syslog(" "); - for (j = 0; j < 16; j++) - { - syslog(" %04x", *run++); - } - up_putc('\n'); - } -} -#endif - -/************************************************************************************** - * Name: ssd1289_showrun - * - * Description: - * When LCD debug is enabled, try to reduce then amount of ouptut data generated by - * ssd1289_putrun and ssd1289_getrun - * - **************************************************************************************/ - -#ifdef CONFIG_DEBUG_LCD -static void ssd1289_showrun(FAR struct ssd1289_dev_s *priv, fb_coord_t row, - fb_coord_t col, size_t npixels, bool put) -{ - fb_coord_t nextrow = priv->lastrow + 1; - - /* Has anything changed (other than the row is the next row in the sequence)? */ - - if (put == priv->put && row == nextrow && col == priv->col && - npixels == priv->npixels) - { - /* No, just update the last row */ - - priv->lastrow = nextrow; - } - else - { - /* Yes... then this is the end of the preceding sequence. Output the last run - * (if there were more than one run in the sequence). - */ - - if (priv->firstrow != priv->lastrow) - { - lcddbg("...\n"); - lcddbg("%s row: %d col: %d npixels: %d\n", - priv->put ? "PUT" : "GET", - priv->lastrow, priv->col, priv->npixels); - } - - /* And we are starting a new sequence. Output the first run of the - * new sequence - */ - - lcddbg("%s row: %d col: %d npixels: %d\n", - put ? "PUT" : "GET", row, col, npixels); - - /* And save information about the run so that we can detect continuations - * of the sequence. - */ - - priv->put = put; - priv->firstrow = row; - priv->lastrow = row; - priv->col = col; - priv->npixels = npixels; - } -} -#endif - -/************************************************************************************** - * Name: ssd1289_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD: - * - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int ssd1289_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - FAR struct ssd1289_dev_s *priv = &g_lcddev; - FAR struct ssd1289_lcd_s *lcd = priv->lcd; - FAR const uint16_t *src = (FAR const uint16_t*)buffer; - int i; - - /* Buffer must be provided and aligned to a 16-bit address boundary */ - - ssd1289_showrun(priv, row, col, npixels, true); - DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); - - /* Select the LCD */ - - lcd->select(lcd); - - /* Write the run to GRAM. */ - -#ifdef CONFIG_LCD_LANDSCAPE - /* Convert coordinates -- Here the edge away from the row of buttons on - * the STM3240G-EVAL is used as the top. - */ - - /* Write the GRAM data, manually incrementing X */ - - for (i = 0; i < npixels; i++) - { - /* Write the next pixel to this position */ - - ssd1289_setcursor(lcd, col, row); - ssd1289_gramselect(lcd); - ssd1289_gramwrite(lcd, *src); - - /* Increment to the next column */ - - src++; - col++; - } -#elif defined(CONFIG_LCD_RLANDSCAPE) - /* Convert coordinates -- Here the edge next to the row of buttons on - * the STM3240G-EVAL is used as the top. - */ - - col = (SSD1289_XRES-1) - col; - row = (SSD1289_YRES-1) - row; - - /* Set the cursor position */ - - ssd1289_setcursor(lcd, col, row); - - /* Then write the GRAM data, auto-decrementing X */ - - ssd1289_gramselect(lcd); - for (i = 0; i < npixels; i++) - { - /* Write the next pixel to this position (auto-decrements to the next column) */ - - ssd1289_gramwrite(lcd, *src); - src++; - } -#elif defined(CONFIG_LCD_PORTRAIT) - /* Convert coordinates. In this configuration, the top of the display is to the left - * of the buttons (if the board is held so that the buttons are at the botton of the - * board). - */ - - col = (SSD1289_XRES-1) - col; - - /* Then write the GRAM data, manually incrementing Y (which is col) */ - - for (i = 0; i < npixels; i++) - { - /* Write the next pixel to this position */ - - ssd1289_setcursor(lcd, row, col); - ssd1289_gramselect(lcd); - ssd1289_gramwrite(lcd, *src); - - /* Increment to the next column */ - - src++; - col--; - } -#else /* CONFIG_LCD_RPORTRAIT */ - /* Convert coordinates. In this configuration, the top of the display is to the right - * of the buttons (if the board is held so that the buttons are at the botton of the - * board). - */ - - row = (SSD1289_YRES-1) - row; - - /* Then write the GRAM data, manually incrementing Y (which is col) */ - - for (i = 0; i < npixels; i++) - { - /* Write the next pixel to this position */ - - ssd1289_setcursor(lcd, row, col); - ssd1289_gramselect(lcd); - ssd1289_gramwrite(lcd, *src); - - /* Decrement to the next column */ - - src++; - col++; - } -#endif - - /* De-select the LCD */ - - lcd->deselect(lcd); - return OK; -} - -/************************************************************************************** - * Name: ssd1289_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int ssd1289_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ -#ifndef CONFIG_LCD_NOGETRUN - FAR struct ssd1289_dev_s *priv = &g_lcddev; - FAR struct ssd1289_lcd_s *lcd = priv->lcd; - FAR uint16_t *dest = (FAR uint16_t*)buffer; - uint16_t accum; - int i; - - /* Buffer must be provided and aligned to a 16-bit address boundary */ - - ssd1289_showrun(priv, row, col, npixels, false); - DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); - - /* Select the LCD */ - - lcd->select(lcd); - - /* Read the run from GRAM. */ - -#ifdef CONFIG_LCD_LANDSCAPE - /* Convert coordinates -- Here the edge away from the row of buttons on - * the STM3240G-EVAL is used as the top. - */ - - for (i = 0; i < npixels; i++) - { - /* Read the next pixel from this position */ - - ssd1289_setcursor(lcd, row, col); - ssd1289_gramselect(lcd); - ssd1289_readsetup(lcd, &accum); - *dest++ = ssd1289_gramread(lcd, &accum); - - /* Increment to the next column */ - - col++; - } -#elif defined(CONFIG_LCD_RLANDSCAPE) - /* Convert coordinates -- Here the edge next to the row of buttons on - * the STM3240G-EVAL is used as the top. - */ - - col = (SSD1289_XRES-1) - col; - row = (SSD1289_YRES-1) - row; - - /* Set the cursor position */ - - ssd1289_setcursor(lcd, col, row); - - /* Then read the GRAM data, auto-decrementing Y */ - - ssd1289_gramselect(lcd); - - /* Prime the pump for unaligned read data */ - - ssd1289_readsetup(lcd, &accum); - - for (i = 0; i < npixels; i++) - { - /* Read the next pixel from this position (autoincrements to the next row) */ - - *dest++ = ssd1289_gramread(lcd, &accum); - } -#elif defined(CONFIG_LCD_PORTRAIT) - /* Convert coordinates. In this configuration, the top of the display is to the left - * of the buttons (if the board is held so that the buttons are at the botton of the - * board). - */ - - col = (SSD1289_XRES-1) - col; - - /* Then read the GRAM data, manually incrementing Y (which is col) */ - - for (i = 0; i < npixels; i++) - { - /* Read the next pixel from this position */ - - ssd1289_setcursor(lcd, row, col); - ssd1289_gramselect(lcd); - ssd1289_readsetup(lcd, &accum); - *dest++ = ssd1289_gramread(lcd, &accum); - - /* Increment to the next column */ - - col--; - } -#else /* CONFIG_LCD_RPORTRAIT */ - /* Convert coordinates. In this configuration, the top of the display is to the right - * of the buttons (if the board is held so that the buttons are at the botton of the - * board). - */ - - row = (SSD1289_YRES-1) - row; - - /* Then write the GRAM data, manually incrementing Y (which is col) */ - - for (i = 0; i < npixels; i++) - { - /* Write the next pixel to this position */ - - ssd1289_setcursor(lcd, row, col); - ssd1289_gramselect(lcd); - ssd1289_readsetup(lcd, &accum); - *dest++ = ssd1289_gramread(lcd, &accum); - - /* Decrement to the next column */ - - col++; - } -#endif - - /* De-select the LCD */ - - lcd->deselect(lcd); - return OK; -#else - return -ENOSYS; -#endif -} - -/************************************************************************************** - * Name: ssd1289_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int ssd1289_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - lcdvdbg("fmt: %d xres: %d yres: %d nplanes: 1\n", - SSD1289_COLORFMT, SSD1289_XRES, SSD1289_YRES); - - vinfo->fmt = SSD1289_COLORFMT; /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - vinfo->xres = SSD1289_XRES; /* Horizontal resolution in pixel columns */ - vinfo->yres = SSD1289_YRES; /* Vertical resolution in pixel rows */ - vinfo->nplanes = 1; /* Number of color planes supported */ - return OK; -} - -/************************************************************************************** - * Name: ssd1289_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int ssd1289_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev; - - DEBUGASSERT(dev && pinfo && planeno == 0); - lcdvdbg("planeno: %d bpp: %d\n", planeno, SSD1289_BPP); - - pinfo->putrun = ssd1289_putrun; /* Put a run into LCD memory */ - pinfo->getrun = ssd1289_getrun; /* Get a run from LCD memory */ - pinfo->buffer = (uint8_t*)priv->runbuffer; /* Run scratch buffer */ - pinfo->bpp = SSD1289_BPP; /* Bits-per-pixel */ - return OK; -} - -/************************************************************************************** - * Name: ssd1289_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ssd1289_getpower(FAR struct lcd_dev_s *dev) -{ - lcdvdbg("power: %d\n", 0); - return g_lcddev.power; -} - -/************************************************************************************** - * Name: ssd1289_poweroff - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ssd1289_poweroff(FAR struct ssd1289_lcd_s *lcd) -{ - /* Set the backlight off */ - - lcd->backlight(lcd, 0); - - /* Turn the display off */ - - ssd1289_putreg(lcd, SSD1289_DSPCTRL, 0); - - /* Remember the power off state */ - - g_lcddev.power = 0; - return OK; -} - -/************************************************************************************** - * Name: ssd1289_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ssd1289_setpower(FAR struct lcd_dev_s *dev, int power) -{ - FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev; - FAR struct ssd1289_lcd_s *lcd = priv->lcd; - - lcdvdbg("power: %d\n", power); - DEBUGASSERT((unsigned)power <= CONFIG_LCD_MAXPOWER); - - /* Set new power level */ - - if (power > 0) - { - /* Set the backlight level */ - - lcd->backlight(lcd, power); - - /* Then turn the display on: - * D=ON(3) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0 - */ - - ssd1289_putreg(lcd, SSD1289_DSPCTRL, - (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_GON | - SSD1289_DSPCTRL_DTE | SSD1289_DSPCTRL_VLE(0))); - - g_lcddev.power = power; - } - else - { - /* Turn the display off */ - - ssd1289_poweroff(lcd); - } - - return OK; -} - -/************************************************************************************** - * Name: ssd1289_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ssd1289_getcontrast(FAR struct lcd_dev_s *dev) -{ - lcdvdbg("Not implemented\n"); - return -ENOSYS; -} - -/************************************************************************************** - * Name: ssd1289_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ssd1289_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast) -{ - lcdvdbg("contrast: %d\n", contrast); - return -ENOSYS; -} - -/************************************************************************************** - * Name: ssd1289_hwinitialize - * - * Description: - * Initialize the LCD hardware. - * - **************************************************************************************/ - -static inline int ssd1289_hwinitialize(FAR struct ssd1289_dev_s *priv) -{ - FAR struct ssd1289_lcd_s *lcd = priv->lcd; -#ifndef CONFIG_LCD_NOGETRUN - uint16_t id; -#endif - int ret; - - /* Select the LCD */ - - lcd->select(lcd); - - /* Read the device ID. Skip verification of the device ID is the LCD is - * write-only. What choice do we have? - */ - -#ifndef CONFIG_LCD_NOGETRUN - id = ssd1289_readreg(lcd, SSD1289_DEVCODE); - if (id != 0) - { - lcddbg("LCD ID: %04x\n", id); - } - - /* If we could not get the ID, then let's just assume that this is an SSD1289. - * Perhaps we have some early register access issues. This seems to happen. - * But then perhaps we should not even bother to read the device ID at all? - */ - - else - { - lcddbg("No LCD ID, assuming SSD1289\n"); - id = SSD1289_DEVCODE_VALUE; - } - - /* Check if the ID is for the SSD1289 */ - - if (id == SSD1289_DEVCODE_VALUE) -#endif - { - /* LCD controller configuration. Many details of the controller initialization - * must, unfortunately, vary from LCD to LCD. I have looked at the spec and at - * three different drivers for LCDs that have SSD1289 controllers. I have tried - * to summarize these differences as profiles (defined above). Some other - * alternatives are noted below. - * - * Most of the differences between LCDs are nothing more than a few minor bit - * settings. The most significant difference betwen LCD drivers in is the - * manner in which the LCD is powered up and in how the power controls are set. - * My suggestion is that if you have working LCD initialization code, you should - * simply replace the following guesses with your working code. - */ - - /* Most drivers just enable the oscillator */ - -#ifdef SSD1289_USE_SIMPLE_INIT - ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN); -#else - /* But one goes through a more complex start-up sequence. Something like the - * following: - * - * First, put the display in INTERNAL operation: - * D=INTERNAL(1) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0 - */ - - ssd1289_putreg(lcd, SSD1289_DSPCTRL, - (SSD1289_DSPCTRL_INTERNAL | SSD1289_DSPCTRL_GON | - SSD1289_DSPCTRL_VLE(0))); - - /* Then enable the oscillator */ - - ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN); - - /* Turn the display on: - * D=ON(3) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0 - */ - - ssd1289_putreg(lcd, SSD1289_DSPCTRL, - (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_GON | - SSD1289_DSPCTRL_VLE(0))); - - /* Take the LCD out of sleep mode */ - - ssd1289_putreg(lcd, SSD1289_SLEEP, 0); - up_mdelay(30); - - /* Turn the display on: - * D=INTERNAL(1) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0 - */ - - ssd1289_putreg(lcd, SSD1289_DSPCTRL, - (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_DTE | - SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(0))); -#endif - - /* Set up power control registers. There is a lot of variability - * from LCD-to-LCD in how the power registers are configured. - */ - - ssd1289_putreg(lcd, SSD1289_PWRCTRL1, PWRCTRL1_SETTING); - ssd1289_putreg(lcd, SSD1289_PWRCTRL2, PWRCTRL2_SETTING); - - /* One driver adds a delay here.. I doubt that this is really necessary. */ - /* up_mdelay(15); */ - - ssd1289_putreg(lcd, SSD1289_PWRCTRL3, PWRCTRL3_SETTING); - ssd1289_putreg(lcd, SSD1289_PWRCTRL4, PWRCTRL4_SETTING); - ssd1289_putreg(lcd, SSD1289_PWRCTRL5, PWRCTRL5_SETTING); - - /* One driver does an odd setting of the the driver output control. - * No idea why. - */ -#if 0 - ssd1289_putreg(lcd, SSD1289_OUTCTRL, - (SSD1289_OUTCTRL_MUX(12) | SSD1289_OUTCTRL_TB | - SSD1289_OUTCTRL_BGR | SSD1289_OUTCTRL_CAD)); - - /* The same driver does another small delay here */ - - up_mdelay(15); -#endif - - /* After this point, the drivers differ only in some varying register - * bit settings. - */ - - /* Set the driver output control. - * PORTRAIT MODES: - * MUX=319, TB=1, SM=0, BGR=1, CAD=0, REV=1, RL=0 - * LANDSCAPE MODES: - * MUX=319, TB=0, SM=0, BGR=1, CAD=0, REV=1, RL=0 - */ - -#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT) - ssd1289_putreg(lcd, SSD1289_OUTCTRL, - (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_TB | - SSD1289_OUTCTRL_BGR | SSD1289_OUTCTRL_REV); -#else - ssd1289_putreg(lcd, SSD1289_OUTCTRL, - (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_BGR | - SSD1289_OUTCTRL_REV)); -#endif - - /* Set the LCD driving AC waveform - * NW=0, WSMD=0, EOR=1, BC=1, ENWD=0, FLD=0 - */ - - ssd1289_putreg(lcd, SSD1289_ACCTRL, - (SSD1289_ACCTRL_EOR | SSD1289_ACCTRL_BC)); - - /* Take the LCD out of sleep mode (isn't this redundant in the non- - * simple case?) - */ - - ssd1289_putreg(lcd, SSD1289_SLEEP, 0); - - /* Set entry mode */ - -#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT) - /* LG=0, AM=0, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3 - * Alternative TY=2 (But TY only applies in 262K color mode anyway) - */ - - ssd1289_putreg(lcd, SSD1289_ENTRY, - (SSD1289_ENTRY_ID_HINCVINC | SSD1289_ENTRY_TY_C | - SSD1289_ENTRY_DMODE_RAM | SSD1289_ENTRY_DFM_65K)); -#else - /* LG=0, AM=1, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3 */ - /* Alternative TY=2 (But TY only applies in 262K color mode anyway) */ - - ssd1289_putreg(lcd, SSD1289_ENTRY, - (SSD1289_ENTRY_AM | SSD1289_ENTRY_ID_HINCVINC | - SSD1289_ENTRY_TY_C | SSD1289_ENTRY_DMODE_RAM | - SSD1289_ENTRY_DFM_65K)); -#endif - - /* Clear compare registers */ - - ssd1289_putreg(lcd, SSD1289_CMP1, 0); - ssd1289_putreg(lcd, SSD1289_CMP2, 0); - - /* One driver puts a huge, 100 millisecond delay here */ - /* up_mdelay(100); */ - - /* Set Horizontal and vertical porch. - * Horizontal porch: 239 pixels per line, delay=28 - * Vertical porch: VBP=3, XFP=0 - */ - - ssd1289_putreg(lcd, SSD1289_HPORCH, - (28 << SSD1289_HPORCH_HBP_SHIFT) | (239 << SSD1289_HPORCH_XL_SHIFT)); - ssd1289_putreg(lcd, SSD1289_VPORCH, - (3 << SSD1289_VPORCH_VBP_SHIFT) | (0 << SSD1289_VPORCH_XFP_SHIFT)); - - /* Set display control. - * D=ON(3), CM=0 (not 8-color), DTE=1, GON=1, SPT=0, VLE=1 PT=0 - */ - - ssd1289_putreg(lcd, SSD1289_DSPCTRL, - (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_DTE | - SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(1))); - - /* Frame cycle control. Alternative: SSD1289_FCYCCTRL_DIV8 */ - - ssd1289_putreg(lcd, SSD1289_FCYCCTRL, 0); - - /* Gate scan start position = 0 */ - - ssd1289_putreg(lcd, SSD1289_GSTART, 0); - - /* Clear vertical scrolling */ - - ssd1289_putreg(lcd, SSD1289_VSCROLL1, 0); - ssd1289_putreg(lcd, SSD1289_VSCROLL2, 0); - - /* Setup window 1 (0-319) */ - - ssd1289_putreg(lcd, SSD1289_W1START, 0); - ssd1289_putreg(lcd, SSD1289_W1END, 319); - - /* Disable window 2 (0-0) */ - - ssd1289_putreg(lcd, SSD1289_W2START, 0); - ssd1289_putreg(lcd, SSD1289_W2END, 0); - - /* Horizontal start and end (0-239) */ - - ssd1289_putreg(lcd, SSD1289_HADDR, - (0 << SSD1289_HADDR_HSA_SHIFT) | (239 << SSD1289_HADDR_HEA_SHIFT)); - - /* Vertical start and end (0-319) */ - - ssd1289_putreg(lcd, SSD1289_VSTART, 0); - ssd1289_putreg(lcd, SSD1289_VEND, 319); - - /* Gamma controls */ - - ssd1289_putreg(lcd, SSD1289_GAMMA1, 0x0707); - ssd1289_putreg(lcd, SSD1289_GAMMA2, 0x0204); /* Alternative: 0x0704 */ - ssd1289_putreg(lcd, SSD1289_GAMMA3, 0x0204); - ssd1289_putreg(lcd, SSD1289_GAMMA4, 0x0502); - ssd1289_putreg(lcd, SSD1289_GAMMA5, 0x0507); - ssd1289_putreg(lcd, SSD1289_GAMMA6, 0x0204); - ssd1289_putreg(lcd, SSD1289_GAMMA7, 0x0204); - ssd1289_putreg(lcd, SSD1289_GAMMA8, 0x0502); - ssd1289_putreg(lcd, SSD1289_GAMMA9, 0x0302); - ssd1289_putreg(lcd, SSD1289_GAMMA10, 0x0302); /* Alternative: 0x1f00 */ - - /* Clear write mask */ - - ssd1289_putreg(lcd, SSD1289_WRMASK1, 0); - ssd1289_putreg(lcd, SSD1289_WRMASK2, 0); - - /* Set frame frequency = 65Hz (This should not be necessary since this - * is the default POR value) - */ - - ssd1289_putreg(lcd, SSD1289_FFREQ, SSD1289_FFREQ_OSC_FF65); - - /* Set the cursor at the home position and set the index register to - * the gram data register (I can't imagine these are necessary). - */ - - ssd1289_setcursor(lcd, 0, 0); - ssd1289_gramselect(lcd); - - /* One driver has a 50 msec delay here */ - /* up_mdelay(50); */ - - ret = OK; - } -#ifndef CONFIG_LCD_NOGETRUN - else - { - lcddbg("Unsupported LCD type\n"); - ret = -ENODEV; - } -#endif - - /* De-select the LCD */ - - lcd->deselect(lcd); - return ret; -} - - /************************************************************************************* - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ssd1289_lcdinitialize - * - * Description: - * Initialize the LCD video hardware. The initial state of the LCD is fully - * initialized, display memory cleared, and the LCD ready to use, but with the power - * setting at 0 (full off). - * - **************************************************************************************/ - -FAR struct lcd_dev_s *ssd1289_lcdinitialize(FAR struct ssd1289_lcd_s *lcd) -{ - int ret; - - lcdvdbg("Initializing\n"); - - /* If we ccould support multiple SSD1289 devices, this is where we would allocate - * a new driver data structure... but we can't. Why not? Because of a bad should - * the form of the getrun() and putrun methods. - */ - - FAR struct ssd1289_dev_s *priv = &g_lcddev; - - /* Initialize the driver data structure */ - - priv->dev.getvideoinfo = ssd1289_getvideoinfo; - priv->dev.getplaneinfo = ssd1289_getplaneinfo; - priv->dev.getpower = ssd1289_getpower; - priv->dev.setpower = ssd1289_setpower; - priv->dev.getcontrast = ssd1289_getcontrast; - priv->dev.setcontrast = ssd1289_setcontrast; - priv->lcd = lcd; - - /* Configure and enable LCD */ - - ret = ssd1289_hwinitialize(priv); - if (ret == OK) - { - /* Clear the display (setting it to the color 0=black) */ - - ssd1289_clear(&priv->dev, 0); - - /* Turn the display off */ - - ssd1289_poweroff(lcd); - return &g_lcddev.dev; - } - - return NULL; -} - -/************************************************************************************** - * Name: ssd1289_clear - * - * Description: - * This is a non-standard LCD interface just for the stm3240g-EVAL board. Because - * of the various rotations, clearing the display in the normal way by writing a - * sequences of runs that covers the entire display can be very slow. Here the - * display is cleared by simply setting all GRAM memory to the specified color. - * - **************************************************************************************/ - -void ssd1289_clear(FAR struct lcd_dev_s *dev, uint16_t color) -{ - FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev; - FAR struct ssd1289_lcd_s *lcd = priv->lcd; - uint32_t i; - - /* Select the LCD and home the cursor position */ - - lcd->select(lcd); - ssd1289_setcursor(lcd, 0, 0); - - /* Prepare to write GRAM data */ - - ssd1289_gramselect(lcd); - - /* Copy color into all of GRAM. Orientation does not matter in this case. */ - - for (i = 0; i < SSD1289_XRES * SSD1289_YRES; i++) - { - ssd1289_gramwrite(lcd, color); - } - - /* De-select the LCD */ - - lcd->deselect(lcd); -} - -#endif /* CONFIG_LCD_SSD1289 */ diff --git a/nuttx/drivers/lcd/ssd1289.h b/nuttx/drivers/lcd/ssd1289.h deleted file mode 100644 index 6d5d1c3cb..000000000 --- a/nuttx/drivers/lcd/ssd1289.h +++ /dev/null @@ -1,425 +0,0 @@ -/************************************************************************************** - * drivers/lcd/ssd1289.h - * Definitions for the Solomon Systech SSD1289 LCD controller - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: SSD1289, Rev 1.3, Apr 2007, Solomon Systech Limited - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -#ifndef __DRIVERS_LCD_SSD1289_H -#define __DRIVERS_LCD_SSD1289_H - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#ifdef CONFIG_LCD_SSD1289 - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ - -/* SSD1289 Register Addresses (All with DC=1) */ - -#define SSD1289_OSCSTART 0x00 /* Oscillation Start (write) */ -#define SSD1289_DEVCODE 0x00 /* Oscillation Start (read) */ -#define SSD1289_OUTCTRL 0x01 /* Driver output control */ -#define SSD1289_ACCTRL 0x02 /* LCD drive AC control */ -#define SSD1289_PWRCTRL1 0x03 /* Power control 1 */ -#define SSD1289_CMP1 0x05 /* Compare register 1 */ -#define SSD1289_CMP2 0x06 /* Compare register 2 */ -#define SSD1289_DSPCTRL 0x07 /* Display control */ -#define SSD1289_FCYCCTRL 0x0b /* Frame cycle control */ -#define SSD1289_PWRCTRL2 0x0c /* Power control 2 */ -#define SSD1289_PWRCTRL3 0x0d /* Power control 3 */ -#define SSD1289_PWRCTRL4 0x0e /* Power control 4 */ -#define SSD1289_GSTART 0x0f /* Gate scan start position */ -#define SSD1289_SLEEP 0x10 /* Sleep mode */ -#define SSD1289_ENTRY 0x11 /* Entry mode */ -#define SSD1289_OPT3 0x12 /* Optimize Access Speed 3 */ -#define SSD1289_GIFCTRL 0x15 /* Generic Interface Control */ -#define SSD1289_HPORCH 0x16 /* Horizontal Porch */ -#define SSD1289_VPORCH 0x17 /* Vertical Porch */ -#define SSD1289_PWRCTRL5 0x1e /* Power control 5 */ -#define SSD1289_DATA 0x22 /* RAM data/write data */ -#define SSD1289_WRMASK1 0x23 /* RAM write data mask 1 */ -#define SSD1289_WRMASK2 0x24 /* RAM write data mask 2 */ -#define SSD1289_FFREQ 0x25 /* Frame Frequency */ -#define SSD1289_VCOMOTP1 0x28 /* VCOM OTP */ -#define SSD1289_OPT1 0x28 /* Optimize Access Speed 1 */ -#define SSD1289_VCOMOTP2 0x29 /* VCOM OTP */ -#define SSD1289_OPT2 0x2f /* Optimize Access Speed 2 */ -#define SSD1289_GAMMA1 0x30 /* Gamma control 1 */ -#define SSD1289_GAMMA2 0x31 /* Gamma control 2 */ -#define SSD1289_GAMMA3 0x32 /* Gamma control 3 */ -#define SSD1289_GAMMA4 0x33 /* Gamma control 4 */ -#define SSD1289_GAMMA5 0x34 /* Gamma control 5 */ -#define SSD1289_GAMMA6 0x35 /* Gamma control 6 */ -#define SSD1289_GAMMA7 0x36 /* Gamma control 7 */ -#define SSD1289_GAMMA8 0x37 /* Gamma control 8 */ -#define SSD1289_GAMMA9 0x3a /* Gamma control 9 */ -#define SSD1289_GAMMA10 0x3b /* Gamma control 10 */ -#define SSD1289_VSCROLL1 0x41 /* Vertical scroll control 1 */ -#define SSD1289_VSCROLL2 0x42 /* Vertical scroll control 2 */ -#define SSD1289_HADDR 0x44 /* Horizontal RAM address position */ -#define SSD1289_VSTART 0x45 /* Vertical RAM address start position */ -#define SSD1289_VEND 0x46 /* Vertical RAM address end position */ -#define SSD1289_W1START 0x48 /* First window start */ -#define SSD1289_W1END 0x49 /* First window end */ -#define SSD1289_W2START 0x4a /* Second window start */ -#define SSD1289_W2END 0x4b /* Second window end */ -#define SSD1289_XADDR 0x4e /* Set GDDRAM X address counter */ -#define SSD1289_YADDR 0x4f /* Set GDDRAM Y address counter */ - -/* SSD1289 Register Bit definitions */ - -/* Index register (DC=0) */ - -#define SSD1289_INDEX_MASK 0xff - -/* Device code (read) */ - -#define SSD1289_DEVCODE_VALUE 0x8989 - -/* Oscillation Start (write) */ - -#define SSD1289_OSCSTART_OSCEN (1 << 0) /* Enable oscillator */ - -/* Driver output control */ - -#define SSD1289_OUTCTRL_MUX_SHIFT (0) /* Number of lines for the LCD driver */ -#define SSD1289_OUTCTRL_MUX_MASK (0x1ff << SSD1289_OUTCTRL_MUX_SHIFT) -# define SSD1289_OUTCTRL_MUX(n) ((n) << SSD1289_OUTCTRL_MUX_SHIFT) -#define SSD1289_OUTCTRL_TB (1 << 9) /* Selects the output shift direction of the gate driver */ -#define SSD1289_OUTCTRL_SM (1 << 10) /* Scanning order of gate driver */ -#define SSD1289_OUTCTRL_BGR (1 << 11) /* Order from RGB to BGR in 18-bit GDDRAM data */ -#define SSD1289_OUTCTRL_CAD (1 << 12) /* Retention capacitor configuration of the TFT panel */ -#define SSD1289_OUTCTRL_REV (1 << 13) /* Reversed display */ -#define SSD1289_OUTCTRL_RL (1 << 14) /* RL pin state */ - -/* LCD drive AC control */ - -#define SSD1289_ACCTRL_NW_SHIFT (0) /* Number of lines to alternate in N-line inversion */ -#define SSD1289_ACCTRL_NW_MASK (0xff << SSD1289_ACCTRL_NW_SHIFT) -#define SSD1289_ACCTRL_WSMD (1 << 8) /* Waveform of WSYNC output */ -#define SSD1289_ACCTRL_EOR (1 << 9) /* EOR signals */ -#define SSD1289_ACCTRL_BC (1 << 10) /* Select the liquid crystal drive waveform */ -#define SSD1289_ACCTRL_ENWS (1 << 11) /* Enables WSYNC output pin */ -#define SSD1289_ACCTRL_FLD (1 << 12) /* Set display in interlace drive mode */ - -/* Power control 1 */ - -#define SSD1289_PWRCTRL1_AP_SHIFT (1) /* Current from internal operational amplifier */ -#define SSD1289_PWRCTRL1_AP_MASK (7 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_LEAST (0 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_SMALL (1 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_SMMED (2 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_MEDIUM (3 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_MEDLG (4 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_LARGE (5 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_LGMX (6 << SSD1289_PWRCTRL1_AP_SHIFT) -# define SSD1289_PWRCTRL1_AP_MAX (7 << SSD1289_PWRCTRL1_AP_SHIFT) -#define SSD1289_PWRCTRL1_DC_SHIFT (4) /* Set the step-up cycle of the step-up circuit for 262k-color mode */ -#define SSD1289_PWRCTRL1_DC_MASK (15 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx24 (0 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx16 (1 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx12 (2 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx8 (3 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx6 (4 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx5 (5 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx4 (6 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx3 (7 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx2 (8 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FLINEx1 (9 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FOSd4 (10 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FOSd6 (11 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FOSd8 (12 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FOSd10 (13 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FOSd12 (14 << SSD1289_PWRCTRL1_DC_SHIFT) -# define SSD1289_PWRCTRL1_DC_FOSd16 (15 << SSD1289_PWRCTRL1_DC_SHIFT) -#define SSD1289_PWRCTRL1_BT_SHIFT (9) /* Control the step-up factor of the step-up circuit */ -#define SSD1289_PWRCTRL1_BT_MASK (7 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p6m5 (0 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p6m4 (1 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p6m6 (2 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p5m5 (3 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p5m4 (4 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p5m3 (5 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p4m4 (6 << SSD1289_PWRCTRL1_BT_SHIFT) -# define SSD1289_PWRCTRL1_BT_p4m3 (7 << SSD1289_PWRCTRL1_BT_SHIFT) -#define SSD1289_PWRCTRL1_DCT_SHIFT (12) /* Step-up cycle of the step-up circuit for 8-color mode */ -#define SSD1289_PWRCTRL1_DCT_MASK (15 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx24 (0 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx16 (1 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx12 (2 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx8 (3 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx6 (4 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx5 (5 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx4 (6 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx3 (7 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx2 (8 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FLINEx1 (9 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FOSd4 (10 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FOSd6 (11 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FOSd8 (12 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FOSd10 (13 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FOSd12 (14 << SSD1289_PWRCTRL1_DCT_SHIFT) -# define SSD1289_PWRCTRL1_DCT_FOSd16 (15 << SSD1289_PWRCTRL1_DCT_SHIFT) - -/* Compare register 1 and 2 */ - -#define SSD1289_CMP1_CPG_SHIFT (2) -#define SSD1289_CMP1_CPG_MASK (0x3f << SSD1289_CMP1_CPG_SHIFT) -#define SSD1289_CMP1_CPR_SHIFT (10) -#define SSD1289_CMP1_CPR_MASK (0x3f << SSD1289_CMP1_CPR_SHIFT) - -#define SSD1289_CMP2_CPB_SHIFT (2) -#define SSD1289_CMP2_CPB_MASK (0x3f << SSD1289_CMP2_CPB_SHIFT) - -/* Display control */ - -#define SSD1289_DSPCTRL_D_SHIFT (0) /* Display control */ -#define SSD1289_DSPCTRL_D_MASK (3 << SSD1289_DSPCTRL_D_SHIFT) -# define SSD1289_DSPCTRL_OFF (0 << SSD1289_DSPCTRL_D_SHIFT) -# define SSD1289_DSPCTRL_INTERNAL (1 << SSD1289_DSPCTRL_D_SHIFT) -# define SSD1289_DSPCTRL_ON (3 << SSD1289_DSPCTRL_D_SHIFT) -#define SSD1289_DSPCTRL_CM (1 << 3) /* 8-color mode setting */ -#define SSD1289_DSPCTRL_DTE (1 << 4) /* Selected gate level */ -#define SSD1289_DSPCTRL_GON (1 << 5) /* Gate off level */ -#define SSD1289_DSPCTRL_SPT (1 << 8) /* 2-division LCD drive */ -#define SSD1289_DSPCTRL_VLE_SHIFT (9) /* Vertical scroll control */ -#define SSD1289_DSPCTRL_VLE_MASK (3 << SSD1289_DSPCTRL_VLE_SHIFT) -# define SSD1289_DSPCTRL_VLE(n) ((n) << SSD1289_DSPCTRL_VLE_SHIFT) -#define SSD1289_DSPCTRL_PT_SHIFT (11) /* Normalize the source outputs */ -#define SSD1289_DSPCTRL_PT_MASK (3 << SSD1289_DSPCTRL_PT_SHIFT) -# define SSD1289_DSPCTRL_PT(n) ((n) << SSD1289_DSPCTRL_PT_SHIFT) - -/* Frame cycle control */ - -#define SSD1289_FCYCCTRL_RTN_SHIFT (0) /* Number of clocks in each line */ -#define SSD1289_FCYCCTRL_RTN_MASK (3 << SSD1289_FCYCCTRL_RTN_SHIFT) -# define SSD1289_FCYCCTRL_RTN(n) (((n)-16) << SSD1289_FCYCCTRL_RTN_SHIFT) -#define SSD1289_FCYCCTRL_SRTN (1 << 4) /* When SRTN =1, RTN3-0 value will be count */ -#define SSD1289_FCYCCTRL_SDIV (1 << 5) /* When SDIV = 1, DIV1-0 value will be count */ -#define SSD1289_FCYCCTRL_DIV_SHIFT (6) /* Set the division ratio of clocks */ -#define SSD1289_FCYCCTRL_DIV_MASK (3 << SSD1289_FCYCCTRL_DIV_SHIFT) -# define SSD1289_FCYCCTRL_DIV1 (0 << SSD1289_FCYCCTRL_DIV_SHIFT) -# define SSD1289_FCYCCTRL_DIV2 (1 << SSD1289_FCYCCTRL_DIV_SHIFT) -# define SSD1289_FCYCCTRL_DIV4 (2 << SSD1289_FCYCCTRL_DIV_SHIFT) -# define SSD1289_FCYCCTRL_DIV8 (3 << SSD1289_FCYCCTRL_DIV_SHIFT) -#define SSD1289_FCYCCTRL_EQ_SHIFT (8) /* Sets the equalizing period */ -#define SSD1289_FCYCCTRL_EQ_MASK (3 << SSD1289_FCYCCTRL_EQ_SHIFT) -# define SSD1289_FCYCCTRL_EQ(n) (((n)-1) << SSD1289_FCYCCTRL_EQ_SHIFT) /* n = 2-8 clocks */ -#define SSD1289_FCYCCTRL_SDT_SHIFT (12) /* Set delay amount from the gate output */ -#define SSD1289_FCYCCTRL_SDT_MASK (3 << SSD1289_FCYCCTRL_SDT_SHIFT) -# define SSD1289_FCYCCTRL_SDT(n) ((n) << SSD1289_FCYCCTRL_SDT_SHIFT) /* n = 1-3 clocks */ -#define SSD1289_FCYCCTRL_NO_SHIFT (14) /* Sets amount of non-overlap of the gate output */ -#define SSD1289_FCYCCTRL_NO_MASK (3 << SSD1289_FCYCCTRL_NO_SHIFT) -# define SSD1289_FCYCCTRL_NO(n) ((n) << SSD1289_FCYCCTRL_NO_SHIFT) /* n = 1-3 clocks */ - -/* Power control 2 */ - -#define SSD1289_PWRCTRL2_VRC_SHIFT (0) /* Adjust VCIX2 output voltage */ -#define SSD1289_PWRCTRL2_VRC_MASK (7 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p1V (0 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p2V (1 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p3V (2 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p4V (3 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p5V (4 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p6V (5 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p7V (6 << SSD1289_PWRCTRL2_VRC_SHIFT) -# define SSD1289_PWRCTRL2_VRC_5p8V (7 << SSD1289_PWRCTRL2_VRC_SHIFT) - -/* Power control 3 */ - -#define SSD1289_PWRCTRL3_VRH_SHIFT (0) /* Set amplitude magnification of VLCD63 */ -#define SSD1289_PWRCTRL3_VRH_MASK (15 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x1p540 (0 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x1p620 (1 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x1p700 (2 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x1p780 (3 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x1p850 (4 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x1p930 (5 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p020 (6 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p090 (7 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p165 (8 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p245 (9 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p335 (10 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p400 (11 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p500 (12 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p570 (13 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p645 (14 << SSD1289_PWRCTRL3_VRH_SHIFT) -# define SSD1289_PWRCTRL3_VRH_x2p725 (15 << SSD1289_PWRCTRL3_VRH_SHIFT) - -/* Power control 4 */ - -#define SSD1289_PWRCTRL4_VDV_SHIFT (8) /* Set amplitude magnification of VLCD63 */ -#define SSD1289_PWRCTRL4_VDV_MASK (32 << SSD1289_PWRCTRL4_VDV_SHIFT) -# define SSD1289_PWRCTRL4_VDV(n) ((n) << SSD1289_PWRCTRL4_VDV_SHIFT) -#define SSD1289_PWRCTRL4_VCOMG (1 << 13) /* VcomL variable */ - -/* Gate scan start position */ - -#define SSD1289_GSTART_MASK 0x1ff - -/* Sleep mode */ - -#define SSD1289_SLEEP_ON (1 << 0) - -/* Entry mode */ - -#define SSD1289_ENTRY_LG_SHIFT (0) /* Write after comparing */ -#define SSD1289_ENTRY_LG_MASK (7 << SSD1289_ENTRY_LG_SHIFT) -#define SSD1289_ENTRY_AM (1 << 3) /* Address counter direction */ -#define SSD1289_ENTRY_ID_SHIFT (4) /* Address increment mode */ -#define SSD1289_ENTRY_ID_MASK (3 << SSD1289_ENTRY_ID_SHIFT) -# define SSD1289_ENTRY_ID_HDECVDEC (0 << SSD1289_ENTRY_ID_SHIFT) -# define SSD1289_ENTRY_ID_HINCVDEC (1 << SSD1289_ENTRY_ID_SHIFT) -# define SSD1289_ENTRY_ID_HDECVINC (2 << SSD1289_ENTRY_ID_SHIFT) -# define SSD1289_ENTRY_ID_HINCVINC (3 << SSD1289_ENTRY_ID_SHIFT) -#define SSD1289_ENTRY_TY_SHIFT (6) /* RAM data write method */ -#define SSD1289_ENTRY_TY_MASK (3 << SSD1289_ENTRY_TY_SHIFT) -# define SSD1289_ENTRY_TY_A (0 << SSD1289_ENTRY_TY_SHIFT) -# define SSD1289_ENTRY_TY_B (1 << SSD1289_ENTRY_TY_SHIFT) -# define SSD1289_ENTRY_TY_C (2 << SSD1289_ENTRY_TY_SHIFT) -#define SSD1289_ENTRY_DMODE_SHIFT (8) /* Data display mode */ -#define SSD1289_ENTRY_DMODE_MASK (3 << SSD1289_ENTRY_DMODE_SHIFT) -# define SSD1289_ENTRY_DMODE_RAM (0 << SSD1289_ENTRY_DMODE_SHIFT) -# define SSD1289_ENTRY_DMODE_GENERIC (1 << SSD1289_ENTRY_DMODE_SHIFT) -# define SSD1289_ENTRY_DMODE_RAMGEN (2 << SSD1289_ENTRY_DMODE_SHIFT) -# define SSD1289_ENTRY_DMODE_GENRAM (3 << SSD1289_ENTRY_DMODE_SHIFT) -#define SSD1289_ENTRY_WMODE (1 << 10) /* Select source of data in RAM */ -#define SSD1289_ENTRY_OEDEF (1 << 11) /* Define display window */ -#define SSD1289_ENTRY_TRANS (1 << 12) /* Transparent display */ -#define SSD1289_ENTRY_DFM_SHIFT (13) /* Color display mode */ -#define SSD1289_ENTRY_DFM_MASK (3 << SSD1289_ENTRY_DFM_SHIFT) -# define SSD1289_ENTRY_DFM_262K (2 << SSD1289_ENTRY_DFM_SHIFT) -# define SSD1289_ENTRY_DFM_65K (3 << SSD1289_ENTRY_DFM_SHIFT) -#define SSD1289_ENTRY_VSMODE (1 << 15) /* Frame frequency depends on VSYNC */ - -/* Generic Interface Control */ - -#define SSD1289_GIFCTRL_INVVS (1 << 0) /* Sets the signal polarity of DOTCLK pin */ -#define SSD1289_GIFCTRL_INVHS (1 << 1) /* Sets the signal polarity of DEN pin */ -#define SSD1289_GIFCTRL_NVDEN (1 << 2) /* Sets the signal polarity of HSYNC pin */ -#define SSD1289_GIFCTRL_INVDOT (1 << 3) /* Sets the signal polarity of VSYNC pin */ - -/* Horizontal Porch */ - -#define SSD1289_HPORCH_HBP_SHIFT (0) /* Set delay from falling edge of HSYNC signal to data */ -#define SSD1289_HPORCH_HBP_MASK (0xff << SSD1289_HPORCH_HBP_SHIFT) -#define SSD1289_HPORCH_XL_SHIFT (8) /* number of valid pixel per line */ -#define SSD1289_HPORCH_XL_MASK (0xff << SSD1289_HPORCH_XL_SHIFT) - -/* Vertical Porch */ - -#define SSD1289_VPORCH_VBP_SHIFT (0) /* Set delay from falling edge of VSYNC signal to line */ -#define SSD1289_VPORCH_VBP_MASK (0xff << SSD1289_VPORCH_VBP_SHIFT) -#define SSD1289_VPORCH_XFP_SHIFT (8) /* Delay from last line to falling edge of VSYNC of next frame */ -#define SSD1289_VPORCH_XFP_MASK (0xff << SSD1289_VPORCH_XFP_SHIFT) -#define SSD1289_VPORCH_ - -/* Power control 5 */ - -#define SSD1289_PWRCTRL5_VCM_SHIFT (0) /* Set the VcomH voltage */ -#define SSD1289_PWRCTRL5_VCM_MASK (0x3f << SSD1289_PWRCTRL5_VCM_SHIFT) -# define SSD1289_PWRCTRL5_VCM(n) ((n) << SSD1289_PWRCTRL5_VCM_SHIFT) -#define SSD1289_PWRCTRL5_NOTP (1 << 7) /* 1=VCM valid */ - -/* RAM write data mask 1 */ - -#define SSD1289_WRMASK1_WMG_SHIFT (2) -#define SSD1289_WRMASK1_WMG_MASK (0x3f << SSD1289_WRMASK1_WMG_SHIFT) -#define SSD1289_WRMASK1_WMR_SHIFT (10) -#define SSD1289_WRMASK1_WMR_MASK (0x3f << SSD1289_WRMASK1_WMR_SHIFT) - -#define SSD1289_WRMASK2_WMB_SHIFT (2) -#define SSD1289_WRMASK2_WMB_MASK (0x3f << SSD1289_WRMASK2_WMB_SHIFT) - -/* Frame Frequency */ - -#define SSD1289_FFREQ_OSC_SHIFT (12) /* Set the frame frequency */ -#define SSD1289_FFREQ_OSC_MASK (15 << SSD1289_FFREQ_OSC_SHIFT) -# define SSD1289_FFREQ_OSC_FF50 (0 << SSD1289_FFREQ_OSC_SHIFT) -# define SSD1289_FFREQ_OSC_FF55 (2 << SSD1289_FFREQ_OSC_SHIFT) -# define SSD1289_FFREQ_OSC_FF60 (5 << SSD1289_FFREQ_OSC_SHIFT) -# define SSD1289_FFREQ_OSC_FF65 (8 << SSD1289_FFREQ_OSC_SHIFT) -# define SSD1289_FFREQ_OSC_FF70 (10 << SSD1289_FFREQ_OSC_SHIFT) -# define SSD1289_FFREQ_OSC_FF75 (12 << SSD1289_FFREQ_OSC_SHIFT) -# define SSD1289_FFREQ_OSC_FF80 (14 << SSD1289_FFREQ_OSC_SHIFT) - -/* VCOM OTP */ - -#define SSD1289_VCOMOTP1_ACTIVATE 0x0006 -#define SSD1289_VCOMOTP1_FIRE 0x000a -#define SSD1289_VCOMOTP2_ACTIVATE 0x80c0 - -/* Optimize Access Speed 1, 2, 3 (omitted) */ - -/* Gamma control 1-10. Magic values. I won't try to represent the fields. */ - -/* Vertical scroll control 1 and 2 */ - -#define SSD1289_VSCROLL_MASK 0x1ff /* Scroll length */ - -/* Horizontal RAM address position */ - -#define SSD1289_HADDR_HSA_SHIFT (0) /* Window horizontal start address */ -#define SSD1289_HADDR_HSA_MASK (0xff << SSD1289_HADDR_HSA_SHIFT) -#define SSD1289_HADDR_HEA_SHIFT (8) /* Window horizontal end address */ -#define SSD1289_HADDR_HEA_MASK (0xff << SSD1289_HADDR_HEA_SHIFT) - -/* Vertical RAM address start/end position */ - -#define SSD1289_VSTART_MASK 0x1ff /* Window Vertical start address */ -#define SSD1289_VEND_MASK 0x1ff /* Window Vertical end address */ - -/* First window start/end */ - -#define SSD1289_W1START_MASK 0x1ff /* Start line for first screen */ -#define SSD1289_W1END_MASK 0x1ff /* End line for first screen */ - -/* Second window start/end */ - -#define SSD1289_W2START_MASK 0x1ff /* Start line for second screen */ -#define SSD1289_W2END_MASK 0x1ff /* End line for second screen */ - -/* Set GDDRAM X/Y address counter */ - -#define SSD1289_XADDR_MASK 0xff /* GDDRAM X address in the address counter */ -#define SSD1289_YADDR_MASK 0x1ff /* GDDRAM Y address in the address counter */ - -#endif /* CONFIG_LCD_SSD1289 */ -#endif /* __DRIVERS_LCD_SSD1289_H */ diff --git a/nuttx/drivers/lcd/ssd1305.h b/nuttx/drivers/lcd/ssd1305.h deleted file mode 100644 index 34678fa80..000000000 --- a/nuttx/drivers/lcd/ssd1305.h +++ /dev/null @@ -1,211 +0,0 @@ -/************************************************************************************** - * drivers/lcd/ssd1305.h - * Definitions for the Solomon Systech SSD1305 132x64 Dot Matrix OLED/PLED - * Segment/Common Driver with C - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: SSD1305.pdf, "Solomon Systech SSD1305 132x64 Dot Matrix OLED/PLED - * Segment/Common Driver with Controller," Solomon Systech Limited, - * http://www.solomon-systech.com, May, 2008. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -#ifndef __DRIVERS_LCD_SSD1305_H -#define __DRIVERS_LCD_SSD1305_H - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ -/* General Definitions ******************************************************/ - -#define SSD1305_COLORA 0 -#define SSD1305_COLORB 1 -#define SSD1305_COLORC 2 -#define SSD1305_COLORD 3 - -/* Fundamental Commands *****************************************************/ -#define SSD1305_SETCOLL 0x00 /* 0x00-0x0f: Set lower column address */ -# define SSD1305_COLL_MASK 0x0f -#define SSD1305_SETCOLH 0x10 /* 0x10-0x1f: Set higher column address */ -# define SSD1305_COLH_MASK 0x0f -#define SSD1305_ADDRMODE 0x20 /* 0x20: Set memory address mode */ -# define SSD1305_ADDRMODE_HOR 0x00 /* Data 1: Set horizontal address mode */ -# define SSD1305_ADDRMODE_VIRT 0x01 /* Data 1: Set virtal address mode */ -# define SSD1305_ADDRMODE_PAGE 0x02 /* Data 1: Set page address mode */ -#define SSD1305_SETCOLADDR 0x21 /* 0x21: Set column address */ - /* Data 1: Column start address: 0-131 */ - /* Data 2: Column end address: 0-131 */ -#define SSD1305_SETPAGEADDR 0x22 /* 0x22: Set page address */ - /* Data 1: Page start address: 0x00-0x7d */ - /* Data 2: Page end address: 0x00-0x7d */ -#define SSD1305_SETSTARTLINE 0x40 /* 0x40-7f: Set display start line */ -# define SSD1305_STARTLINE_MASK 0x3f - -#define SSD1305_SETCONTRAST 0x81 /* 0x81: Set contrast control */ - /* Data 1: Set 1 of 256 contrast steps */ -#define SSD1305_SETBRIGHTNESS 0x82 /* 0x82: Set brightness */ - /* Data 1: Set 1 of 256 contrast steps */ -#define SSD1305_SETLUT 0x91 /* 0x01: Set lookup table */ - /* Data 1: Pulse width: 31-63 */ - /* Data 2: Color A: 31-63 */ - /* Data 3: Color B: 31-63 */ - /* Data 4: Color C: 31-63 */ -#define SSD1305_SETBANKCOLOR1 0x92 /* 0x92: Set bank 1-16 color */ -# define SSD1305_SETBANK1(c) (c) /* Data 1, Bits 0-1: Bank 1 color */ -# define SSD1305_SETBANK2(c) (c << 2) /* Data 1, Bits 2-3: Bank 2 color */ -# define SSD1305_SETBANK3(c) (c << 4) /* Data 1, Bits 4-5: Bank 3 color */ -# define SSD1305_SETBANK4(c) (c << 6) /* Data 1, Bits 6-7: Bank 4 color */ -# define SSD1305_SETBANK5(c) (c) /* Data 2, Bits 0-1: Bank 5 color */ -# define SSD1305_SETBANK6(c) (c << 2) /* Data 2, Bits 2-3: Bank 6 color */ -# define SSD1305_SETBANK7(c) (c << 4) /* Data 2, Bits 4-5: Bank 7 color */ -# define SSD1305_SETBANK8(c) (c << 6) /* Data 2, Bits 6-7: Bank 8 color */ -# define SSD1305_SETBANK9(c) (c) /* Data 3, Bits 0-1: Bank 9 color */ -# define SSD1305_SETBANK10(c) (c << 2) /* Data 3, Bits 2-3: Bank 10 color */ -# define SSD1305_SETBANK11(c) (c << 4) /* Data 3, Bits 4-5: Bank 11 color */ -# define SSD1305_SETBANK12(c) (c << 6) /* Data 3, Bits 6-7: Bank 12 color */ -# define SSD1305_SETBANK13(c) (c) /* Data 4, Bits 0-1: Bank 13 color */ -# define SSD1305_SETBANK14(c) (c << 2) /* Data 4, Bits 2-3: Bank 14 color */ -# define SSD1305_SETBANK15(c) (c << 4) /* Data 4, Bits 4-5: Bank 15 color */ -# define SSD1305_SETBANK16(c) (c << 6) /* Data 4, Bits 6-7: Bank 16 color */ -#define SSD1305_SETBANKCOLOR2 0x93 /* 0x93: Set bank 17-32 color */ -# define SSD1305_SETBANK17(c) (c) /* Data 1, Bits 0-1: Bank 17 color */ -# define SSD1305_SETBANK18(c) (c << 2) /* Data 1, Bits 2-3: Bank 18 color */ -# define SSD1305_SETBANK19(c) (c << 4) /* Data 1, Bits 4-5: Bank 19 color */ -# define SSD1305_SETBANK20(c) (c << 6) /* Data 1, Bits 6-7: Bank 20 color */ -# define SSD1305_SETBANK21(c) (c) /* Data 2, Bits 0-1: Bank 21 color */ -# define SSD1305_SETBANK22(c) (c << 2) /* Data 2, Bits 2-3: Bank 22 color */ -# define SSD1305_SETBANK23(c) (c << 4) /* Data 2, Bits 4-5: Bank 23 color */ -# define SSD1305_SETBANK24(c) (c << 6) /* Data 2, Bits 6-7: Bank 24 color */ -# define SSD1305_SETBANK25(c) (c) /* Data 3, Bits 0-1: Bank 25 color */ -# define SSD1305_SETBANK26(c) (c << 2) /* Data 3, Bits 2-3: Bank 26 color */ -# define SSD1305_SETBANK27(c) (c << 4) /* Data 3, Bits 4-5: Bank 27 color */ -# define SSD1305_SETBANK28(c) (c << 6) /* Data 3, Bits 6-7: Bank 28 color */ -# define SSD1305_SETBANK29(c) (c) /* Data 4, Bits 0-1: Bank 29 color */ -# define SSD1305_SETBANK30(c) (c << 2) /* Data 4, Bits 2-3: Bank 30 color */ -# define SSD1305_SETBANK31(c) (c << 4) /* Data 4, Bits 4-5: Bank 31 color */ -# define SSD1305_SETBANK32(c) (c << 6) /* Data 4, Bits 6-7: Bank 32 color */ -#define SSD1305_MAPCOL0 0xa0 /* 0xa0: Column address 0 is mapped to SEG0 */ -#define SSD1305_MAPCOL131 0xa1 /* 0xa1: Column address 131 is mapped to SEG0 */ -#define SSD1305_DISPRAM 0xa4 /* 0xa4: Resume to RAM content display */ -#define SSD1305_DISPENTIRE 0xa5 /* 0xa5: Entire display ON */ -#define SSD1305_DISPNORMAL 0xa6 /* 0xa6: Normal display */ -#define SSD1305_DISPINVERTED 0xa7 /* 0xa7: Inverse display */ - -#define SSD1305_SETMUX 0xa8 /* 0xa8: Set Multiplex Ratio*/ - /* Data 1: MUX ratio -1: 15-63 */ -#define SSD1305_DIMMODE 0xab /* 0xab: Dim mode setting */ - /* Data 1: Reserverd, must be zero */ - /* Data 2: Contrast for bank1: 0-255 */ - /* Data 3: Brightness for color bank: 0-255 */ -#define SSD1305_MSTRCONFIG 0xad /* 0xad: Master configuration */ -# define SSD1305_MSTRCONFIG_EXTVCC 0x8e /* Data 1: Select external Vcc */ -#define SSD1305_DISPONDIM 0xac /* 0xac: Display ON in dim mode */ -#define SSD1305_DISPOFF 0xae /* 0xae: Display OFF (sleep mode) */ -#define SSD1305_DISPON 0xaf /* 0xaf: Display ON in normal mode */ -#define SSD1305_SETPAGESTART 0xb0 /* 0xb0-b7: Set page start address */ -# define SSD1305_PAGESTART_MASK 0x07 -#define SSD1305_SETCOMNORMAL 0xc0 /* 0xc0: Set COM output, normal mode */ -#define SSD1305_SETCOMREMAPPED 0xc8 /* 0xc8: Set COM output, remapped mode */ - -#define SSD1305_SETOFFSET 0xd3 /* 0xd3: Set display offset */ - /* Data 1: Vertical shift by COM: 0-63 */ -#define SSD1305_SETDCLK 0xd5 /* 0xd5: Set display clock divide ratio/oscillator */ -# define SSD1305_DCLKDIV_SHIFT (0) /* Data 1, Bits 0-3: DCLK divide ratio/frequency*/ -# define SSD1305_DCLKDIV_MASK 0x0f -# define SSD1305_DCLKFREQ_SHIFT (4) /* Data 1, Bits 4-7: DCLK divide oscillator frequency */ -# define SSD1305_DCLKFREQ_MASK 0xf0 -#define SSD1305_SETCOLORMODE 0xd8 /* 0xd: Set area color and low power display modes */ -# define SSD1305_COLORMODE_MONO 0x00 /* Data 1, Bits 4-5: 00=monochrome */ -# define SSD1305_COLORMODE_COLOR 0x30 /* Data 1, Bits 4-5: 11=area color enable */ -# define SSD1305_POWERMODE_NORMAL 0x00 /* Data 1, Bits 0,2: 00=normal power mode */ -# define SSD1305_POWERMODE_LOW 0x05 /* Data 1, Bits 0,2: 11=low power display mode */ -#define SSD1305_SETPRECHARGE 0xd9 /* 0xd9: Set pre-charge period */ -# define SSD1305_PHASE1_SHIFT (0) /* Data 1, Bits 0-3: Phase 1 period of up to 15 DCLK clocks */ -# define SSD1305_PHASE1_MASK 0x0f -# define SSD1305_PHASE2_SHIFT (4) /* Data 1, Bits 4-7: Phase 2 period of up to 15 DCLK clocks */ -# define SSD1305_PHASE2_MASK 0xf0 -#define SSD1305_SETCOMCONFIG 0xda /* 0xda: Set COM configuration */ -# define SSD1305_COMCONFIG_SEQ 0x02 /* Data 1, Bit 4: 0=Sequential COM pin configuration */ -# define SSD1305_COMCONFIG_ALT 0x12 /* Data 1, Bit 4: 1=Alternative COM pin configuration */ -# define SSD1305_COMCONFIG_NOREMAP 0x02 /* Data 1, Bit 5: 0=Disable COM Left/Right remap */ -# define SSD1305_COMCONFIG_REMAP 0x22 /* Data 1, Bit 5: 1=Enable COM Left/Right remap */ -#define SSD1305_SETVCOMHDESEL 0xdb /* 0xdb: Set VCOMH delselect level */ -# define SSD1305_VCOMH_x4p3 0x00 /* Data 1: ~0.43 x Vcc */ -# define SSD1305_VCOMH_x7p7 0x34 /* Data 1: ~0.77 x Vcc */ -# define SSD1305_VCOMH_x8p3 0x3c /* Data 1: ~0.83 x Vcc */ -#define SSD1305_ENTER_RMWMODE 0xe0 /* 0xe0: Enter the Read Modify Write mode */ -#define SSD1305_NOP 0xe3 /* 0xe3: NOP Command for no operation */ -#define SSD1305_EXIT_RMWMODE 0xee /* 0xee: Leave the Read Modify Write mode */ - -/* Graphic Acceleration Commands ********************************************/ - -#define SSD1305_HSCROLL_RIGHT 0x26 /* 0x26: Right horizontal scroll */ -#define SSD1305_HSCROLL_LEFT 0x27 /* 0x27: Left horizontal scroll */ - /* Data 1, Bits 0-2: Column scroll offset: 0-4 */ - /* Data 2, Bits 0-2: Start page address: 0-7 */ -#define SSD1305_HSCROLL_FRAMES6 0x00 /* Data 3, Bits 0-2: Timer interval, 000=6 frames */ -#define SSD1305_HSCROLL_FRAMES32 0x01 /* Data 3, Bits 0-2: Timer interval, 001=32 frames */ -#define SSD1305_HSCROLL_FRAMES64 0x02 /* Data 3, Bits 0-2: Timer interval, 010=64 frames */ -#define SSD1305_HSCROLL_FRAMES128 0x03 /* Data 3, Bits 0-2: Timer interval, 011=128 frames */ -#define SSD1305_HSCROLL_FRAMES3 0x04 /* Data 3, Bits 0-2: Timer interval, 100=3 frames */ -#define SSD1305_HSCROLL_FRAMES4 0x05 /* Data 3, Bits 0-2: Timer interval, 101=4 frames */ -#define SSD1305_HSCROLL_FRAMES2 0x06 /* Data 3, Bits 0-2: Timer interval, 110=2 frames */ - /* Data 4, Bits 0-2: End page address: 0-7 */ - -#define SSD1305_VSCROLL_RIGHT 0x29 /* 0x26: Vertical and right horizontal scroll */ -#define SSD1305_VSCROLL_LEFT 0x2a /* 0x27: Vertical and left horizontal scroll */ - /* Data 1, Bits 0-2: Column scroll offset: 0-4 */ - /* Data 2, Bits 0-2: Start page address: 0-7 */ -#define SSD1305_VSCROLL_FRAMES6 0x00 /* Data 3, Bits 0-2: Timer interval, 000=6 frames */ -#define SSD1305_VSCROLL_FRAMES32 0x01 /* Data 3, Bits 0-2: Timer interval, 001=32 frames */ -#define SSD1305_VSCROLL_FRAMES64 0x02 /* Data 3, Bits 0-2: Timer interval, 010=64 frames */ -#define SSD1305_VSCROLL_FRAMES128 0x03 /* Data 3, Bits 0-2: Timer interval, 011=128 frames */ -#define SSD1305_VSCROLL_FRAMES3 0x04 /* Data 3, Bits 0-2: Timer interval, 100=3 frames */ -#define SSD1305_VSCROLL_FRAMES4 0x05 /* Data 3, Bits 0-2: Timer interval, 101=4 frames */ -#define SSD1305_VSCROLL_FRAMES2 0x06 /* Data 3, Bits 0-2: Timer interval, 110=2 frames */ - /* Data 4, Bits 0-2: End page address: 0-7 */ - /* Data 5, Bits 0-5: Vertical scrolling offset: 0-63 */ -#define SSD1305_SCROLL_STOP 0x2e /* 0x2e: Deactivate scroll */ -#define SSD1305_SCROLL_START 0x2f /* 0x2f: Activate scroll */ -#define SSD1305_VSCROLL_AREA 0xa3 /* 0xa3: Set vertical scroll area */ - /* Data 1: Number of rows in the top fixed area */ - /* Data 1: Number of rows in the scroll area */ - -/* Status register bit definitions ******************************************/ - -#define SSD1305_STATUS_DISPOFF (1 << 6) /* Bit 6: 1=Display off */ - -#endif /* __DRIVERS_LCD_SSD1305_H */ diff --git a/nuttx/drivers/lcd/ug-2864ambag01.c b/nuttx/drivers/lcd/ug-2864ambag01.c deleted file mode 100644 index 6b3d6d5a8..000000000 --- a/nuttx/drivers/lcd/ug-2864ambag01.c +++ /dev/null @@ -1,1161 +0,0 @@ -/************************************************************************************** - * drivers/lcd/ug-2864ambag01.c - * Driver for Univision UG-2864AMBAG01 OLED display (wih SH1101A controller) in SPI - * mode - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * 1. Product Specification (Preliminary), Part Name: OEL Display Module, Part ID: - * UG-2864AMBAG01, Doc No: SASI-9015-A, Univision Technology Inc. - * 2. SH1101A, 132 X 64 Dot Matrix OLED/PLED, Preliminary Segment/Common Driver with - * Controller, Sino Wealth - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ -/************************************************************************************** - * Device memory organization: - * - * +----------------------------+ - * | Column | - * --------+----+---+---+---+-...-+-----+ - * Page | 0 | 1 | 2 | 3 | ... | 131 | - * --------+----+---+---+---+-...-+-----+ - * Page 0 | D0 | X | | | | | - * | D1 | X | | | | | - * | D2 | X | | | | | - * | D3 | X | | | | | - * | D4 | X | | | | | - * | D5 | X | | | | | - * | D6 | X | | | | | - * | D7 | X | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 1 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 2 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 3 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 4 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 5 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 6 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 7 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * - * -----------------------------------+--------------------------------------- - * Landscape Display: | Reverse Landscape Display: - * --------+-----------------------+ | --------+---------------------------+ - * | Column | | | Column | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 0 | 0 | 1 | 2 | | 131 | | Page 7 | 131 | 130 | 129 | | 0 | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 1 | V | | Page 6 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 2 | V | | Page 5 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 3 | V | | Page 4 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 4 | V | | Page 3 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 5 | V | | Page 2 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 6 | V | | Page 1 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 7 | V | | Page 0 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * -----------------------------------+--------------------------------------- - * - * -----------------------------------+--------------------------------------- - * Portrait Display: | Reverse Portrait Display: - * -----------+---------------------+ | -----------+---------------------+ - * | Page | | | Page | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 0 | 0 | 1 | 2 | | 7 | | Column 131 | 7 | 6 | 5 | | 0 | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 1 | > > > > > | | Column 130 | | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 2 | | | Column 129 | | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * ... | | | ... | | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 131 | | | Column 0 | < < < < < | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * -----------------------------------+---------------------------------------- - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#ifdef CONFIG_LCD_UG2864AMBAG01 - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ -/* Configuration **********************************************************************/ -/* Limitations of the current configuration that I hope to fix someday */ - -#if CONFIG_UG2864AMBAG01_NINTERFACES != 1 -# warning "This implementation supports only a single OLED device" -# undef CONFIG_UG2864AMBAG01_NINTERFACES -# define CONFIG_UG2864AMBAG01_NINTERFACES 1 -#endif - -#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT) -# warning "No support yet for portrait modes" -# define CONFIG_LCD_LANDSCAPE 1 -# undef CONFIG_LCD_PORTRAIT -# undef CONFIG_LCD_RLANDSCAPE -# undef CONFIG_LCD_RPORTRAIT -#elif defined(CONFIG_LCD_RLANDSCAPE) -# warning "Reverse landscape mode is untested and, hence, probably buggy" -#endif - -/* SH1101A Commands *******************************************************************/ - -#define SH1101A_SETCOLL(ad) (0x00 | ((ad) & 0x0f)) /* Set Lower Column Address: (00h - 0fh) */ -#define SH1101A_SETCOLH(ad) (0x10 | ((ad) & 0x0f)) /* Set Higher Column Address: (10h - 1fh) */ -#define SH1101A_STARTLINE(ln) (0x40 | ((ln) & 0x3f)) /* Set Display Start Line: (40h - 7fh) */ -#define SH1101A_CONTRAST_MODE (0x81) /* Set Contrast Control Register: (Double Bytes Command) */ -# define SH1101A_CONTRAST(c) (c) -#define SH1101A_SEGREMAP(m) (0xa0 | ((m) & 0x01)) /* Set Segment Re-map: (a0h - a1h) */ -# define SH1101A_REMAPRIGHT SH1101A_SEGREMAP(0) /* Right rotation */ -# define SH1101A_REMAPPLEFT SH1101A_SEGREMAP(1) /* Left rotation */ -#define SH1101A_EDISPOFFON(s) (0xa4 | ((s) & 0x01)) /* Set Entire Display OFF/ON: (a4h - a5h) */ -# define SH1101A_EDISPOFF SH1101A_EDISPOFFON(0) /* Display off */ -# define SH1101A_EDISPON SH1101A_EDISPOFFON(1) /* Display on */ -#define SH1101A_NORMREV(s) (0xa6 | ((s) & 0x01)) /* Set Normal/Reverse Display: (a6h -a7h) */ -# define SH1101A_NORMAL SH1101A_NORMREV(0) /* Normal display */ -# define SH1101A_REVERSE SH1101A_NORMREV(1) /* Reverse display */ -#define SH1101A_MRATIO_MODE (0xa8) /* Set Multiplex Ration: (Double Bytes Command) */ -# define SH1101A_MRATIO(d) ((d) & 0x3f) -#define SH1101A_DCDC_MODE (0xad) /* Set DC-DC OFF/ON: (Double Bytes Command) */ -# define SH1101A_DCDC_OFF (0x8a) - # define SH1101A_DCDC_ON (0x8b) -#define SH1101A_DISPOFFON(s) (0xae | ((s) & 0x01)) /* Display OFF/ON: (aeh - afh) */ -# define SH1101A_DISPOFF SH1101A_DISPOFFON(0) /* Display off */ -# define SH1101A_DISPON SH1101A_DISPOFFON(1) /* Display on */ -#define SH1101A_PAGEADDR(a) (0xb0 | ((a) & 0x0f)) /* Set Page Address: (b0h - b7h) */ -#define SH1101A_SCANDIR(d) (0xc0 | ((d) & 0x08)) /* Set Common Output Scan Direction: (c0h - c8h) */ -# define SH1101A_SCANFROMCOM0 SH1101A_SCANDIR(0x00) /* Scan from COM[0] to COM[n-1]*/ -# define SH1101A_SCANTOCOM0 SH1101A_SCANDIR(0x08) /* Scan from COM[n-1] to COM[0] */ -#define SH1101A_DISPOFFS_MODE (0xd3) /* Set Display Offset: (Double Bytes Command) */ -# define SH1101A_DISPOFFS(o) ((o) & 0x3f) -#define SH1101A_CLKDIV_SET (0xd5) /* Set Display Clock Divide Ratio/Oscillator Frequency: (Double Bytes Command) */ -# define SH1101A_CLKDIV(f,d) ((((f) & 0x0f) << 4) | ((d) & 0x0f)) -#define SH1101A_CHRGPER_SET (0xd9) /* Set Dis-charge/Pre-charge Period: (Double Bytes Command) */ -# define SH1101A_CHRGPER(d,p) ((((d) & 0x0f) << 4) | ((p) & 0x0f)) -#define SH1101A_CMNPAD_CONFIG (0xda) /* Set Common pads hardware configuration: (Double Bytes Command) */ - #define SH1101A_CMNPAD(c) ((0x02) | ((c) & 0x10)) -#define SH1101A_VCOM_SET (0xdb) /* Set VCOM Deselect Level: (Double Bytes Command) */ -# define SH1101A_VCOM(v) (v) -#define SH1101A_RMWSTART (0xe0) /* Read-Modify-Write: (e0h) */ -#define SH1101A_NOP (0xe3) /* NOP: (e3h) */ -#define SH1101A_END (0xee) /* End: (eeh) */ - -#define SH1101A_WRDATA(d) (d) /* Write Display Data */ -#define SH1101A_STATUS_BUSY (0x80) /* Read Status */ -#define SH1101A_STATUS_ONOFF (0x40) -#define SH1101A_RDDATA(d) (d) /* Read Display Data */ - -/* Color Properties *******************************************************************/ -/* Display Resolution - * - * The SH1101A display controller can handle a resolution of 132x64. The UG-2864AMBAG01 - * on the base board is 128x64. - */ - -#define UG2864AMBAG01_DEV_XRES 128 /* Only 128 of 131 columns used */ -#define UG2864AMBAG01_DEV_YRES 64 /* 8 pages each 8 rows */ -#define UG2864AMBAG01_DEV_XOFFSET 2 /* Offset to logical column 0 */ -#define UG2864AMBAG01_DEV_PAGES 8 /* 8 pages */ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -# define UG2864AMBAG01_XRES UG2864AMBAG01_DEV_XRES -# define UG2864AMBAG01_YRES UG2864AMBAG01_DEV_YRES -#else -# define UG2864AMBAG01_XRES UG2864AMBAG01_DEV_YRES -# define UG2864AMBAG01_YRES UG2864AMBAG01_DEV_XRES -#endif - -/* Color depth and format */ - -#define UG2864AMBAG01_BPP 1 -#define UG2864AMBAG01_COLORFMT FB_FMT_Y1 - -/* Bytes per logical row and actual device row */ - -#define UG2864AMBAG01_XSTRIDE (UG2864AMBAG01_XRES >> 3) -#define UG2864AMBAG01_YSTRIDE (UG2864AMBAG01_YRES >> 3) - -/* Default contrast */ - -#define UG2864AMBAG01_CONTRAST (128) - -/* The size of the shadow frame buffer or one row buffer. - * - * Frame buffer size: 128 columns x 64 rows / 8 bits-per-pixel - * Row size: 128 columns x 8 rows-per-page / 8 bits-per-pixel - */ - -#define UG2864AMBAG01_FBSIZE (UG2864AMBAG01_XSTRIDE * UG2864AMBAG01_YRES) -#define UG2864AMBAG01_ROWSIZE (UG2864AMBAG01_XSTRIDE) - -/* Bit helpers */ - -#define LS_BIT (1 << 0) -#define MS_BIT (1 << 7) - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_DEBUG_LCD -# define lcddbg(format, arg...) dbg(format, ##arg) -# define lcdvdbg(format, arg...) vdbg(format, ##arg) -#else -# define lcddbg(x...) -# define lcdvdbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct ug2864ambag01_dev_s -{ - struct lcd_dev_s dev; /* Publically visible device structure */ - - /* Private LCD-specific information follows */ - - FAR struct spi_dev_s *spi; /* Cached SPI device reference */ - uint8_t contrast; /* Current contrast setting */ - bool on; /* true: display is on */ - - - /* The SH1101A does not support reading from the display memory in SPI mode. - * Since there is 1 BPP and access is byte-by-byte, it is necessary to keep - * a shadow copy of the framebuffer memory. At 128x64, this amounts to 1KB. - */ - - uint8_t fb[UG2864AMBAG01_FBSIZE]; -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ - -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ug2864ambag01_configspi(FAR struct spi_dev_s *spi); -# define ug2864ambag01_lock(spi) -# define ug2864ambag01_unlock(spi) -#else -# define ug2864ambag01_configspi(spi) -static void ug2864ambag01_lock(FAR struct spi_dev_s *spi); -static void ug2864ambag01_unlock(FAR struct spi_dev_s *spi); -#endif - -/* LCD Data Transfer Methods */ - -static int ug2864ambag01_putrun(fb_coord_t row, fb_coord_t col, - FAR const uint8_t *buffer, size_t npixels); -static int ug2864ambag01_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int ug2864ambag01_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int ug2864ambag01_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int ug2864ambag01_getpower(struct lcd_dev_s *dev); -static int ug2864ambag01_setpower(struct lcd_dev_s *dev, int power); -static int ug2864ambag01_getcontrast(struct lcd_dev_s *dev); -static int ug2864ambag01_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - -static uint8_t g_runbuffer[UG2864AMBAG01_ROWSIZE]; - -/* This structure describes the overall LCD video controller */ - -static const struct fb_videoinfo_s g_videoinfo = -{ - .fmt = UG2864AMBAG01_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - .xres = UG2864AMBAG01_XRES, /* Horizontal resolution in pixel columns */ - .yres = UG2864AMBAG01_YRES, /* Vertical resolution in pixel rows */ - .nplanes = 1, /* Number of color planes supported */ -}; - -/* This is the standard, NuttX Plane information object */ - -static const struct lcd_planeinfo_s g_planeinfo = -{ - .putrun = ug2864ambag01_putrun, /* Put a run into LCD memory */ - .getrun = ug2864ambag01_getrun, /* Get a run from LCD memory */ - .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */ - .bpp = UG2864AMBAG01_BPP, /* Bits-per-pixel */ -}; - -/* This is the OLED driver instance (only a single device is supported for now) */ - -static struct ug2864ambag01_dev_s g_oleddev = -{ - .dev = - { - /* LCD Configuration */ - - .getvideoinfo = ug2864ambag01_getvideoinfo, - .getplaneinfo = ug2864ambag01_getplaneinfo, - - /* LCD RGB Mapping -- Not supported */ - /* Cursor Controls -- Not supported */ - - /* LCD Specific Controls */ - - .getpower = ug2864ambag01_getpower, - .setpower = ug2864ambag01_setpower, - .getcontrast = ug2864ambag01_getcontrast, - .setcontrast = ug2864ambag01_setcontrast, - }, -}; - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ug2864ambag01_configspi - * - * Description: - * Configure the SPI for use with the UG-2864AMBAG01 - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ug2864ambag01_configspi(FAR struct spi_dev_s *spi) -{ - lcdvdbg("Mode: %d Bits: 8 Frequency: %d\n", - CONFIG_UG2864AMBAG01_SPIMODE, CONFIG_UG2864AMBAG01_FREQUENCY); - - /* Configure SPI for the UG-2864AMBAG01. But only if we own the SPI bus. Otherwise, - * don't bother because it might change. - */ - - SPI_SETMODE(spi, CONFIG_UG2864AMBAG01_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_UG2864AMBAG01_FREQUENCY); -} -#endif - -/************************************************************************************** - * Name: ug2864ambag01_lock - * - * Description: - * Select the SPI, locking and re-configuring if necessary - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static inline void ug2864ambag01_lock(FAR struct spi_dev_s *spi) -{ - /* Lock the SPI bus if there are multiple devices competing for the SPI bus. */ - - SPI_LOCK(spi, true); - - /* Now make sure that the SPI bus is configured for the UG-2864AMBAG01 (it - * might have gotten configured for a different device while unlocked) - */ - - SPI_SETMODE(spi, CONFIG_UG2864AMBAG01_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_UG2864AMBAG01_FREQUENCY); -} -#endif - -/************************************************************************************** - * Name: ug2864ambag01_unlock - * - * Description: - * De-select the SPI - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static inline void ug2864ambag01_unlock(FAR struct spi_dev_s *spi) -{ - /* De-select UG-2864AMBAG01 chip and relinquish the SPI bus. */ - - SPI_LOCK(spi, false); -} -#endif - -/************************************************************************************** - * Name: ug2864ambag01_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD. - * - * Input Parameters: - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -static int ug2864ambag01_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - /* Because of this line of code, we will only be able to support a single UG device */ - - FAR struct ug2864ambag01_dev_s *priv = (FAR struct ug2864ambag01_dev_s *)&g_oleddev; - FAR uint8_t *fbptr; - FAR uint8_t *ptr; - uint8_t devcol; - uint8_t fbmask; - uint8_t page; - uint8_t usrmask; - int pixlen; - uint8_t i; - - lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Clip the run to the display */ - - pixlen = npixels; - if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG2864AMBAG01_XRES) - { - pixlen = (int)UG2864AMBAG01_XRES - (int)col; - } - - /* Verify that some portion of the run remains on the display */ - - if (pixlen <= 0 || row > UG2864AMBAG01_YRES) - { - return OK; - } - - /* Perform coordinate conversion for reverse landscape mode */ - -#ifdef CONFIG_LCD_RLANDSCAPE - row = (UG2864AMBAG01_YRES-1) - row; - col = (UG2864AMBAG01_XRES-1) - col; -#endif - - /* Get the page number. The range of 64 lines is divided up into eight - * pages of 8 lines each. - */ - - page = row >> 3; - - /* Update the shadow frame buffer memory. First determine the pixel - * position in the frame buffer memory. Pixels are organized like - * this: - * - * --------+---+---+---+---+-...-+-----+ - * Segment | 0 | 1 | 2 | 3 | ... | 131 | - * --------+---+---+---+---+-...-+-----+ - * D0 | | X | | | | | - * D1 | | X | | | | | - * D2 | | X | | | | | - * D3 | | X | | | | | - * D4 | | X | | | | | - * D5 | | X | | | | | - * D6 | | X | | | | | - * D7 | | X | | | | | - * --------+---+---+---+---+-...-+-----+ - * - * So, in order to draw a white, horizontal line, at row 45. we - * would have to modify all of the bytes in page 45/8 = 5. We - * would have to set bit 45%8 = 5 in every byte in the page. - */ - - fbmask = 1 << (row & 7); - fbptr = &priv->fb[page * UG2864AMBAG01_XRES + col]; -#ifdef CONFIG_LCD_RLANDSCAPE - ptr = fbptr + pixlen - 1; -#else - ptr = fbptr; -#endif -#ifdef CONFIG_NX_PACKEDMSFIRST - usrmask = MS_BIT; -#else - usrmask = LS_BIT; -#endif - - for (i = 0; i < pixlen; i++) - { - /* Set or clear the corresponding bit */ - -#ifdef CONFIG_LCD_RLANDSCAPE - if ((*buffer & usrmask) != 0) - { - *ptr-- |= fbmask; - } - else - { - *ptr-- &= ~fbmask; - } -#else - if ((*buffer & usrmask) != 0) - { - *ptr++ |= fbmask; - } - else - { - *ptr++ &= ~fbmask; - } -#endif - - /* Inc/Decrement to the next source pixel */ - -#ifdef CONFIG_NX_PACKEDMSFIRST - if (usrmask == LS_BIT) - { - buffer++; - usrmask = MS_BIT; - } - else - { - usrmask >>= 1; - } -#else - if (usrmask == MS_BIT) - { - buffer++; - usrmask = LS_BIT; - } - else - { - usrmask <<= 1; - } -#endif - } - - /* Offset the column position to account for smaller horizontal - * display range. - */ - - devcol = col + UG2864AMBAG01_DEV_XOFFSET; - - /* Lock and select device */ - - ug2864ambag01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the starting position for the run */ - /* Set the column address to the XOFFSET value */ - - SPI_SEND(priv->spi, SH1101A_SETCOLL(devcol & 0x0f)); - SPI_SEND(priv->spi, SH1101A_SETCOLH(devcol >> 4)); - - /* Set the page address */ - - SPI_SEND(priv->spi, SH1101A_PAGEADDR(page)); - - /* Select data transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, false); - - /* Then transfer all of the data */ - - (void)SPI_SNDBLOCK(priv->spi, fbptr, pixlen); - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864ambag01_unlock(priv->spi); - return OK; -} -#else -# error "Configuration not implemented" -#endif - -/************************************************************************************** - * Name: ug2864ambag01_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * Description: - * This method can be used to write a partial raster line to the LCD. - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -static int ug2864ambag01_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ - /* Because of this line of code, we will only be able to support a single UG device */ - - FAR struct ug2864ambag01_dev_s *priv = &g_oleddev; - FAR uint8_t *fbptr; - uint8_t page; - uint8_t fbmask; - uint8_t usrmask; - int pixlen; - uint8_t i; - - lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Clip the run to the display */ - - pixlen = npixels; - if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG2864AMBAG01_XRES) - { - pixlen = (int)UG2864AMBAG01_XRES - (int)col; - } - - /* Verify that some portion of the run is actually the display */ - - if (pixlen <= 0 || row > UG2864AMBAG01_YRES) - { - return -EINVAL; - } - - /* Perform coordinate conversion for reverse landscape mode */ - -#ifdef CONFIG_LCD_RLANDSCAPE - row = (UG2864AMBAG01_YRES-1) - row; - col = (UG2864AMBAG01_XRES-1) - col; -#endif - - /* Then transfer the display data from the shadow frame buffer memory */ - /* Get the page number. The range of 64 lines is divided up into eight - * pages of 8 lines each. - */ - - page = row >> 3; - - /* Update the shadow frame buffer memory. First determine the pixel - * position in the frame buffer memory. Pixels are organized like - * this: - * - * --------+---+---+---+---+-...-+-----+ - * Segment | 0 | 1 | 2 | 3 | ... | 131 | - * --------+---+---+---+---+-...-+-----+ - * D0 | | X | | | | | - * D1 | | X | | | | | - * D2 | | X | | | | | - * D3 | | X | | | | | - * D4 | | X | | | | | - * D5 | | X | | | | | - * D6 | | X | | | | | - * D7 | | X | | | | | - * --------+---+---+---+---+-...-+-----+ - * - * So, in order to draw a white, horizontal line, at row 45. we - * would have to modify all of the bytes in page 45/8 = 5. We - * would have to set bit 45%8 = 5 in every byte in the page. - */ - - fbmask = 1 << (row & 7); -#ifdef CONFIG_LCD_RLANDSCAPE - fbptr = &priv->fb[page * (UG2864AMBAG01_XRES-1) + col + pixlen]; -#else - fbptr = &priv->fb[page * UG2864AMBAG01_XRES + col]; -#endif -#ifdef CONFIG_NX_PACKEDMSFIRST - usrmask = MS_BIT; -#else - usrmask = LS_BIT; -#endif - - *buffer = 0; - for (i = 0; i < pixlen; i++) - { - /* Set or clear the corresponding bit */ - -#ifdef CONFIG_LCD_RLANDSCAPE - uint8_t byte = *fbptr--; -#else - uint8_t byte = *fbptr++; -#endif - if ((byte & fbmask) != 0) - { - *buffer |= usrmask; - } - - /* Inc/Decrement to the next destination pixel. Hmmmm. It looks like - * this logic could write past the end of the user buffer. Revisit - * this! - */ - -#ifdef CONFIG_NX_PACKEDMSFIRST - if (usrmask == LS_BIT) - { - buffer++; - *buffer = 0; - usrmask = MS_BIT; - } - else - { - usrmask >>= 1; - } -#else - if (usrmask == MS_BIT) - { - buffer++; - *buffer = 0; - usrmask = LS_BIT; - } - else - { - usrmask <<= 1; - } -#endif - } - - return OK; -} -#else -# error "Configuration not implemented" -#endif - -/************************************************************************************** - * Name: ug2864ambag01_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int ug2864ambag01_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - lcdvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", - g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes); - memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: ug2864ambag01_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int ug2864ambag01_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - DEBUGASSERT(pinfo && planeno == 0); - lcdvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp); - memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: ug2864ambag01_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ug2864ambag01_getpower(FAR struct lcd_dev_s *dev) -{ - FAR struct ug2864ambag01_dev_s *priv = (FAR struct ug2864ambag01_dev_s *)dev; - DEBUGASSERT(priv); - - lcdvdbg("power: %s\n", priv->on ? "ON" : "OFF"); - return priv->on ? CONFIG_LCD_MAXPOWER : 0; -} - -/************************************************************************************** - * Name: ug2864ambag01_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ug2864ambag01_setpower(struct lcd_dev_s *dev, int power) -{ - struct ug2864ambag01_dev_s *priv = (struct ug2864ambag01_dev_s *)dev; - DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER && priv->spi); - - lcdvdbg("power: %d [%d]\n", power, priv->on ? CONFIG_LCD_MAXPOWER : 0); - - /* Lock and select device */ - - ug2864ambag01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - if (power <= 0) - { - /* Turn the display off */ - - (void)SPI_SEND(priv->spi, SH1101A_DISPOFF); - priv->on = false; - } - else - { - /* Turn the display on */ - - (void)SPI_SEND(priv->spi, SH1101A_DISPON); /* Display on, dim mode */ - priv->on = true; - } - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864ambag01_unlock(priv->spi); - return OK; -} - -/************************************************************************************** - * Name: ug2864ambag01_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ug2864ambag01_getcontrast(struct lcd_dev_s *dev) -{ - struct ug2864ambag01_dev_s *priv = (struct ug2864ambag01_dev_s *)dev; - DEBUGASSERT(priv); - - lcdvdbg("contrast: %d\n", priv->contrast); - return priv->contrast; -} - -/************************************************************************************** - * Name: ug2864ambag01_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ug2864ambag01_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) -{ - struct ug2864ambag01_dev_s *priv = (struct ug2864ambag01_dev_s *)dev; - unsigned int scaled; - - lcdvdbg("contrast: %d\n", contrast); - DEBUGASSERT(priv); - - /* Verify the contrast value */ - -#ifdef CONFIG_DEBUG - if (contrast > CONFIG_LCD_MAXCONTRAST) - { - return -EINVAL; - } -#endif - - /* Scale contrast: newcontrast = 255 * contrast / CONFIG_LCD_MAXCONTRAST - * Where contrast is in the range {1,255} - */ - -#if CONFIG_LCD_MAXCONTRAST != 255 - scaled = ((contrast << 8) - 1) / CONFIG_LCD_MAXCONTRAST; -#else - scaled = contrast; -#endif - - /* Lock and select device */ - - ug2864ambag01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the contrast */ - - (void)SPI_SEND(priv->spi, SH1101A_CONTRAST_MODE); /* Set contrast control register */ - (void)SPI_SEND(priv->spi, SH1101A_CONTRAST(scaled)); /* Data 1: Set 1 of 256 contrast steps */ - priv->contrast = contrast; - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864ambag01_unlock(priv->spi); - return OK; -} - -/************************************************************************************** - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ug2864ambag01_initialize - * - * Description: - * Initialize the UG-2864AMBAG01 video hardware. The initial state of the - * OLED is fully initialized, display memory cleared, and the OLED ready - * to use, but with the power setting at 0 (full off == sleep mode). - * - * Input Parameters: - * - * spi - A reference to the SPI driver instance. - * devno - A value in the range of 0 through CONFIG_UG2864AMBAG01_NINTERFACES-1. - * This allows support for multiple OLED devices. - * - * Returned Value: - * - * On success, this function returns a reference to the LCD object for - * the specified OLED. NULL is returned on any failure. - * - **************************************************************************************/ - -FAR struct lcd_dev_s *ug2864ambag01_initialize(FAR struct spi_dev_s *spi, unsigned int devno) -{ - FAR struct ug2864ambag01_dev_s *priv = &g_oleddev; - - lcdvdbg("Initializing\n"); - DEBUGASSERT(spi && devno == 0); - - /* Save the reference to the SPI device */ - - priv->spi = spi; - - /* Configure the SPI */ - - ug2864ambag01_configspi(spi); - - /* Lock and select device */ - - ug2864ambag01_lock(priv->spi); - SPI_SELECT(spi, SPIDEV_DISPLAY, true); - - /* Select command transfer */ - - SPI_CMDDATA(spi, SPIDEV_DISPLAY, true); - - /* Configure the device */ - - SPI_SEND(spi, SH1101A_DISPOFF); /* Display off */ - SPI_SEND(spi, SH1101A_SETCOLL(0)); /* Set lower column address */ - SPI_SEND(spi, SH1101A_SETCOLH(0)); /* Set higher column address */ - SPI_SEND(spi, SH1101A_STARTLINE(0)); /* Set display start line */ - SPI_SEND(spi, SH1101A_PAGEADDR(0)); /* Set page address */ - SPI_SEND(spi, SH1101A_CONTRAST_MODE); /* Contrast control */ - SPI_SEND(spi ,UG2864AMBAG01_CONTRAST); /* Default contrast */ - SPI_SEND(spi, SH1101A_REMAPPLEFT); /* Set segment remap left */ - SPI_SEND(spi, SH1101A_EDISPOFF); /* Normal display */ - SPI_SEND(spi, SH1101A_NORMAL); /* Normal (un-reversed) display mode */ - SPI_SEND(spi, SH1101A_MRATIO_MODE); /* Multiplex ratio */ - SPI_SEND(spi, SH1101A_MRATIO(0x3f)); /* Duty = 1/64 */ - SPI_SEND(spi, SH1101A_SCANTOCOM0); /* Com scan direction: Scan from COM[n-1] to COM[0] */ - SPI_SEND(spi, SH1101A_DISPOFFS_MODE); /* Set display offset */ - SPI_SEND(spi, SH1101A_DISPOFFS(0)); - SPI_SEND(spi, SH1101A_CLKDIV_SET); /* Set clock divider */ - SPI_SEND(spi, SH1101A_CLKDIV(0,0)); - SPI_SEND(spi, SH1101A_CMNPAD_CONFIG); /* Set common pads */ - SPI_SEND(spi, SH1101A_CMNPAD(0x10)); - SPI_SEND(spi, SH1101A_VCOM_SET); - SPI_SEND(spi, SH1101A_VCOM(0x40)); - SPI_SEND(spi, SH1101A_DCDC_MODE); /* DC/DC control mode: on */ - SPI_SEND(spi, SH1101A_DCDC_ON); - SPI_SEND(spi, SH1101A_DISPON); /* display ON */ - - /* De-select and unlock the device */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, false); - ug2864ambag01_unlock(priv->spi); - - /* Clear the display */ - - up_mdelay(100); - ug2864ambag01_fill(&priv->dev, UG_Y1_BLACK); - return &priv->dev; -} - -/************************************************************************************** - * Name: ug2864ambag01_fill - * - * Description: - * This non-standard method can be used to clear the entire display by writing one - * color to the display. This is much faster than writing a series of runs. - * - * Input Parameters: - * priv - Reference to private driver structure - * - * Assumptions: - * Caller has selected the OLED section. - * - **************************************************************************************/ - -void ug2864ambag01_fill(FAR struct lcd_dev_s *dev, uint8_t color) -{ - FAR struct ug2864ambag01_dev_s *priv = &g_oleddev; - unsigned int page; - - /* Make an 8-bit version of the selected color */ - - if (color & 1) - { - color = 0xff; - } - else - { - color = 0; - } - - /* Initialize the framebuffer */ - - memset(priv->fb, color, UG2864AMBAG01_FBSIZE); - - /* Lock and select device */ - - ug2864ambag01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - /* Visit each page */ - - for (page = 0; page < UG2864AMBAG01_DEV_PAGES; page++) - { - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the column address to the XOFFSET value */ - - SPI_SEND(priv->spi, SH1101A_SETCOLL(UG2864AMBAG01_DEV_XOFFSET)); - SPI_SEND(priv->spi, SH1101A_SETCOLH(0)); - - /* Set the page address */ - - SPI_SEND(priv->spi, SH1101A_PAGEADDR(page)); - - /* Select data transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, false); - - /* Transfer one page of the selected color */ - - (void)SPI_SNDBLOCK(priv->spi, &priv->fb[page * UG2864AMBAG01_XRES], - UG2864AMBAG01_XRES); - } - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864ambag01_unlock(priv->spi); -} - -#endif /* CONFIG_LCD_UG2864AMBAG01 */ diff --git a/nuttx/drivers/lcd/ug-2864hsweg01.c b/nuttx/drivers/lcd/ug-2864hsweg01.c deleted file mode 100644 index 02a59b104..000000000 --- a/nuttx/drivers/lcd/ug-2864hsweg01.c +++ /dev/null @@ -1,1218 +0,0 @@ -/************************************************************************************** - * drivers/lcd/ug-2864hsweg01.c - * Driver for Univision UG-2864HSWEG01 OLED display (wih SSD1306 controller) in SPI - * mode - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * 1. Product Specification (Preliminary), Part Name: OEL Display Module, Part ID: - * UG-2864HSWEG01, Doc No: SAS1-9046-B, Univision Technology Inc. - * 2. SSD1306, 128 X 64 Dot Matrix OLED/PLED, Preliminary Segment/Common Driver with - * Controller, Solomon Systech - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ -/************************************************************************************** - * Device memory organization: - * - * +----------------------------+ - * | Column | - * --------+----+---+---+---+-...-+-----+ - * Page | 0 | 1 | 2 | 3 | ... | 127 | - * --------+----+---+---+---+-...-+-----+ - * Page 0 | D0 | X | | | | | - * | D1 | X | | | | | - * | D2 | X | | | | | - * | D3 | X | | | | | - * | D4 | X | | | | | - * | D5 | X | | | | | - * | D6 | X | | | | | - * | D7 | X | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 1 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 2 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 3 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 4 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 5 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 6 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * Page 7 | | | | | | | - * --------+----+---+---+---+-...-+-----+ - * - * -----------------------------------+--------------------------------------- - * Landscape Display: | Reverse Landscape Display: - * --------+-----------------------+ | --------+---------------------------+ - * | Column | | | Column | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 0 | 0 | 1 | 2 | | 127 | | Page 7 | 127 | 126 | 125 | | 0 | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 1 | V | | Page 6 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 2 | V | | Page 5 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 3 | V | | Page 4 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 4 | V | | Page 3 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 5 | V | | Page 2 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 6 | V | | Page 1 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * Page 7 | V | | Page 0 | ^ | - * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+ - * -----------------------------------+--------------------------------------- - * - * -----------------------------------+--------------------------------------- - * Portrait Display: | Reverse Portrait Display: - * -----------+---------------------+ | -----------+---------------------+ - * | Page | | | Page | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 0 | 0 | 1 | 2 | | 7 | | Column 127 | 7 | 6 | 5 | | 0 | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 1 | > > > > > | | Column 126 | | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 2 | | | Column 125 | | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * ... | | | ... | | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * Column 127 | | | Column 0 | < < < < < | - * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+ - * -----------------------------------+---------------------------------------- - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#ifdef CONFIG_LCD_UG2864HSWEG01 - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ -/* Configuration **********************************************************************/ -/* Limitations of the current configuration that I hope to fix someday */ - -#if CONFIG_UG2864HSWEG01_NINTERFACES != 1 -# warning "This implementation supports only a single OLED device" -# undef CONFIG_UG2864HSWEG01_NINTERFACES -# define CONFIG_UG2864HSWEG01_NINTERFACES 1 -#endif - -#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT) -# warning "No support yet for portrait modes" -# define CONFIG_LCD_LANDSCAPE 1 -# undef CONFIG_LCD_PORTRAIT -# undef CONFIG_LCD_RLANDSCAPE -# undef CONFIG_LCD_RPORTRAIT -#elif defined(CONFIG_LCD_RLANDSCAPE) -# warning "Reverse landscape mode is untested and, hence, probably buggy" -#endif - -/* SSD1306 Commands *******************************************************************/ - -#define SSD1306_SETCOLL(ad) (0x00 | ((ad) & 0x0f)) /* Set Lower Column Address: (00h - 0fh) */ -#define SSD1306_SETCOLH(ad) (0x10 | ((ad) & 0x0f)) /* Set Higher Column Address: (10h - 1fh) */ -#define SSD1306_STARTLINE(ln) (0x40 | ((ln) & 0x3f)) /* Set Display Start Line: (40h - 7fh) */ -#define SSD1306_CONTRAST_MODE (0x81) /* Set Contrast Control Register: (Double Bytes Command) */ -# define SSD1306_CONTRAST(c) (c) -#define SSD1306_SEGREMAP(m) (0xa0 | ((m) & 0x01)) /* Set Segment Re-map: (a0h - a1h) */ -# define SSD1306_REMAPRIGHT SSD1306_SEGREMAP(0) /* Right rotation */ -# define SSD1306_REMAPPLEFT SSD1306_SEGREMAP(1) /* Left rotation */ -#define SSD1306_EDISPOFFON(s) (0xa4 | ((s) & 0x01)) /* Set Entire Display OFF/ON: (a4h - a5h) */ -# define SSD1306_EDISPOFF SSD1306_EDISPOFFON(0) /* Display off */ -# define SSD1306_EDISPON SSD1306_EDISPOFFON(1) /* Display on */ -#define SSD1306_NORMREV(s) (0xa6 | ((s) & 0x01)) /* Set Normal/Reverse Display: (a6h -a7h) */ -# define SSD1306_NORMAL SSD1306_NORMREV(0) /* Normal display */ -# define SSD1306_REVERSE SSD1306_NORMREV(1) /* Reverse display */ -#define SSD1306_MRATIO_MODE (0xa8) /* Set Multiplex Ration: (Double Bytes Command) */ -# define SSD1306_MRATIO(d) ((d) & 0x3f) -#define SSD1306_DCDC_MODE (0xad) /* Set DC-DC OFF/ON: (Double Bytes Command) */ -# define SSD1306_DCDC_OFF (0x8a) -# define SSD1306_DCDC_ON (0x8b) - -#define SSD1306_DISPOFFON(s) (0xae | ((s) & 0x01)) /* Display OFF/ON: (aeh - afh) */ -# define SSD1306_DISPOFF SSD1306_DISPOFFON(0) /* Display off */ -# define SSD1306_DISPON SSD1306_DISPOFFON(1) /* Display on */ -#define SSD1306_PAGEADDR(a) (0xb0 | ((a) & 0x0f)) /* Set Page Address: (b0h - b7h) */ -#define SSD1306_SCANDIR(d) (0xc0 | ((d) & 0x08)) /* Set Common Output Scan Direction: (c0h - c8h) */ -# define SSD1306_SCANFROMCOM0 SSD1306_SCANDIR(0x00) /* Scan from COM[0] to COM[n-1]*/ -# define SSD1306_SCANTOCOM0 SSD1306_SCANDIR(0x08) /* Scan from COM[n-1] to COM[0] */ -#define SSD1306_DISPOFFS_MODE (0xd3) /* Set Display Offset: (Double Bytes Command) */ -# define SSD1306_DISPOFFS(o) ((o) & 0x3f) -#define SSD1306_CLKDIV_SET (0xd5) /* Set Display Clock Divide Ratio/Oscillator Frequency: (Double Bytes Command) */ -# define SSD1306_CLKDIV(f,d) ((((f) & 0x0f) << 4) | ((d) & 0x0f)) -#define SSD1306_CHRGPER_SET (0xd9) /* Set Dis-charge/Pre-charge Period: (Double Bytes Command) */ -# define SSD1306_CHRGPER(d,p) ((((d) & 0x0f) << 4) | ((p) & 0x0f)) -#define SSD1306_CMNPAD_CONFIG (0xda) /* Set Common pads hardware configuration: (Double Bytes Command) */ -# define SSD1306_CMNPAD(c) ((0x02) | ((c) & 0x10)) -#define SSD1306_VCOM_SET (0xdb) /* Set VCOM Deselect Level: (Double Bytes Command) */ -# define SSD1306_VCOM(v) (v) - -#define SSD1306_CHRPUMP_SET (0x8d) /* Charge Pump Setting */ -# define SSD1306_CHRPUMP_ON (0x14) -# define SSD1306_CHRPUMP_OFF (0x10) - -#define SSD1306_RMWSTART (0xe0) /* Read-Modify-Write: (e0h) */ -#define SSD1306_NOP (0xe3) /* NOP: (e3h) */ -#define SSD1306_END (0xee) /* End: (eeh) */ - -#define SSD1306_WRDATA(d) (d) /* Write Display Data */ -#define SSD1306_STATUS_BUSY (0x80) /* Read Status */ -#define SSD1306_STATUS_ONOFF (0x40) -#define SSD1306_RDDATA(d) (d) /* Read Display Data */ - -/* Color Properties *******************************************************************/ -/* Display Resolution - * - * The SSD1306 display controller can handle a resolution of 132x64. The UG-2864HSWEG01 - * on the base board is 128x64. - */ - -#define UG2864HSWEG01_DEV_XRES 128 /* Only 128 of 131 columns used */ -#define UG2864HSWEG01_DEV_YRES 64 /* 8 pages each 8 rows */ -#define UG2864HSWEG01_DEV_XOFFSET 2 /* Offset to logical column 0 */ -#define UG2864HSWEG01_DEV_PAGES 8 /* 8 pages */ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -# define UG2864HSWEG01_XRES UG2864HSWEG01_DEV_XRES -# define UG2864HSWEG01_YRES UG2864HSWEG01_DEV_YRES -#else -# define UG2864HSWEG01_XRES UG2864HSWEG01_DEV_YRES -# define UG2864HSWEG01_YRES UG2864HSWEG01_DEV_XRES -#endif - -/* Color depth and format */ - -#define UG2864HSWEG01_BPP 1 -#define UG2864HSWEG01_COLORFMT FB_FMT_Y1 - -/* Bytes per logical row and actual device row */ - -#define UG2864HSWEG01_XSTRIDE (UG2864HSWEG01_XRES >> 3) -#define UG2864HSWEG01_YSTRIDE (UG2864HSWEG01_YRES >> 3) - -/* Default contrast */ - -#define UG2864HSWEG01_CONTRAST (128) - -/* The size of the shadow frame buffer or one row buffer. - * - * Frame buffer size: 128 columns x 64 rows / 8 bits-per-pixel - * Row size: 128 columns x 8 rows-per-page / 8 bits-per-pixel - */ - -#define UG2864HSWEG01_FBSIZE (UG2864HSWEG01_XSTRIDE * UG2864HSWEG01_YRES) -#define UG2864HSWEG01_ROWSIZE (UG2864HSWEG01_XSTRIDE) - -/* Bit helpers */ - -#define LS_BIT (1 << 0) -#define MS_BIT (1 << 7) - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_DEBUG_LCD -# define lcddbg(format, arg...) dbg(format, ##arg) -# define lcdvdbg(format, arg...) vdbg(format, ##arg) -#else -# define lcddbg(x...) -# define lcdvdbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct ug2864hsweg01_dev_s -{ - struct lcd_dev_s dev; /* Publically visible device structure */ - - /* Private LCD-specific information follows */ - - FAR struct spi_dev_s *spi; /* Cached SPI device reference */ - uint8_t contrast; /* Current contrast setting */ - bool on; /* true: display is on */ - - - /* The SSD1306 does not support reading from the display memory in SPI mode. - * Since there is 1 BPP and access is byte-by-byte, it is necessary to keep - * a shadow copy of the framebuffer memory. At 128x64, this amounts to 1KB. - */ - - uint8_t fb[UG2864HSWEG01_FBSIZE]; -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ - -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ug2864hsweg01_configspi(FAR struct spi_dev_s *spi); -# define ug2864hsweg01_lock(spi) -# define ug2864hsweg01_unlock(spi) -#else -# define ug2864hsweg01_configspi(spi) -static void ug2864hsweg01_lock(FAR struct spi_dev_s *spi); -static void ug2864hsweg01_unlock(FAR struct spi_dev_s *spi); -#endif - -/* LCD Data Transfer Methods */ - -static int ug2864hsweg01_putrun(fb_coord_t row, fb_coord_t col, - FAR const uint8_t *buffer, size_t npixels); -static int ug2864hsweg01_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int ug2864hsweg01_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int ug2864hsweg01_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int ug2864hsweg01_getpower(struct lcd_dev_s *dev); -static int ug2864hsweg01_setpower(struct lcd_dev_s *dev, int power); -static int ug2864hsweg01_getcontrast(struct lcd_dev_s *dev); -static int ug2864hsweg01_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - -static uint8_t g_runbuffer[UG2864HSWEG01_ROWSIZE]; - -/* This structure describes the overall LCD video controller */ - -static const struct fb_videoinfo_s g_videoinfo = -{ - .fmt = UG2864HSWEG01_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - .xres = UG2864HSWEG01_XRES, /* Horizontal resolution in pixel columns */ - .yres = UG2864HSWEG01_YRES, /* Vertical resolution in pixel rows */ - .nplanes = 1, /* Number of color planes supported */ -}; - -/* This is the standard, NuttX Plane information object */ - -static const struct lcd_planeinfo_s g_planeinfo = -{ - .putrun = ug2864hsweg01_putrun, /* Put a run into LCD memory */ - .getrun = ug2864hsweg01_getrun, /* Get a run from LCD memory */ - .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */ - .bpp = UG2864HSWEG01_BPP, /* Bits-per-pixel */ -}; - -/* This is the OLED driver instance (only a single device is supported for now) */ - -static struct ug2864hsweg01_dev_s g_oleddev = -{ - .dev = - { - /* LCD Configuration */ - - .getvideoinfo = ug2864hsweg01_getvideoinfo, - .getplaneinfo = ug2864hsweg01_getplaneinfo, - - /* LCD RGB Mapping -- Not supported */ - /* Cursor Controls -- Not supported */ - - /* LCD Specific Controls */ - - .getpower = ug2864hsweg01_getpower, - .setpower = ug2864hsweg01_setpower, - .getcontrast = ug2864hsweg01_getcontrast, - .setcontrast = ug2864hsweg01_setcontrast, - }, -}; - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ug2864hsweg01_configspi - * - * Description: - * Configure the SPI for use with the UG-2864HSWEG01 - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ug2864hsweg01_configspi(FAR struct spi_dev_s *spi) -{ - lcdvdbg("Mode: %d Bits: 8 Frequency: %d\n", - CONFIG_UG2864HSWEG01_SPIMODE, CONFIG_UG2864HSWEG01_FREQUENCY); - - /* Configure SPI for the UG-2864HSWEG01. But only if we own the SPI bus. Otherwise, - * don't bother because it might change. - */ - - SPI_SETMODE(spi, CONFIG_UG2864HSWEG01_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_UG2864HSWEG01_FREQUENCY); -} -#endif - -/************************************************************************************** - * Name: ug2864hsweg01_lock - * - * Description: - * Select the SPI, locking and re-configuring if necessary - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static inline void ug2864hsweg01_lock(FAR struct spi_dev_s *spi) -{ - /* Lock the SPI bus if there are multiple devices competing for the SPI bus. */ - - SPI_LOCK(spi, true); - - /* Now make sure that the SPI bus is configured for the UG-2864HSWEG01 (it - * might have gotten configured for a different device while unlocked) - */ - - SPI_SETMODE(spi, CONFIG_UG2864HSWEG01_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_UG2864HSWEG01_FREQUENCY); -} -#endif - -/************************************************************************************** - * Name: ug2864hsweg01_unlock - * - * Description: - * De-select the SPI - * - * Input Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static inline void ug2864hsweg01_unlock(FAR struct spi_dev_s *spi) -{ - /* De-select UG-2864HSWEG01 chip and relinquish the SPI bus. */ - - SPI_LOCK(spi, false); -} -#endif - -/************************************************************************************** - * Name: ug2864hsweg01_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD. - * - * Input Parameters: - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -static int ug2864hsweg01_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - /* Because of this line of code, we will only be able to support a single UG device */ - - FAR struct ug2864hsweg01_dev_s *priv = (FAR struct ug2864hsweg01_dev_s *)&g_oleddev; - FAR uint8_t *fbptr; - FAR uint8_t *ptr; - uint8_t devcol; - uint8_t fbmask; - uint8_t page; - uint8_t usrmask; - int pixlen; - uint8_t i; - - lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Clip the run to the display */ - - pixlen = npixels; - if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG2864HSWEG01_XRES) - { - pixlen = (int)UG2864HSWEG01_XRES - (int)col; - } - - /* Verify that some portion of the run remains on the display */ - - if (pixlen <= 0 || row > UG2864HSWEG01_YRES) - { - return OK; - } - - /* Perform coordinate conversion for reverse landscape mode */ - -#ifdef CONFIG_LCD_RLANDSCAPE - row = (UG2864HSWEG01_YRES-1) - row; - col = (UG2864HSWEG01_XRES-1) - col; -#endif - - /* Get the page number. The range of 64 lines is divided up into eight - * pages of 8 lines each. - */ - - page = row >> 3; - - /* Update the shadow frame buffer memory. First determine the pixel - * position in the frame buffer memory. Pixels are organized like - * this: - * - * --------+---+---+---+---+-...-+-----+ - * Segment | 0 | 1 | 2 | 3 | ... | 131 | - * --------+---+---+---+---+-...-+-----+ - * D0 | | X | | | | | - * D1 | | X | | | | | - * D2 | | X | | | | | - * D3 | | X | | | | | - * D4 | | X | | | | | - * D5 | | X | | | | | - * D6 | | X | | | | | - * D7 | | X | | | | | - * --------+---+---+---+---+-...-+-----+ - * - * So, in order to draw a white, horizontal line, at row 45. we - * would have to modify all of the bytes in page 45/8 = 5. We - * would have to set bit 45%8 = 5 in every byte in the page. - */ - - fbmask = 1 << (row & 7); - fbptr = &priv->fb[page * UG2864HSWEG01_XRES + col]; -#ifdef CONFIG_LCD_RLANDSCAPE - ptr = fbptr + pixlen - 1; -#else - ptr = fbptr; -#endif -#ifdef CONFIG_NX_PACKEDMSFIRST - usrmask = MS_BIT; -#else - usrmask = LS_BIT; -#endif - - for (i = 0; i < pixlen; i++) - { - /* Set or clear the corresponding bit */ - -#ifdef CONFIG_LCD_RLANDSCAPE - if ((*buffer & usrmask) != 0) - { - *ptr-- |= fbmask; - } - else - { - *ptr-- &= ~fbmask; - } -#else - if ((*buffer & usrmask) != 0) - { - *ptr++ |= fbmask; - } - else - { - *ptr++ &= ~fbmask; - } -#endif - - /* Inc/Decrement to the next source pixel */ - -#ifdef CONFIG_NX_PACKEDMSFIRST - if (usrmask == LS_BIT) - { - buffer++; - usrmask = MS_BIT; - } - else - { - usrmask >>= 1; - } -#else - if (usrmask == MS_BIT) - { - buffer++; - usrmask = LS_BIT; - } - else - { - usrmask <<= 1; - } -#endif - } - - /* Offset the column position to account for smaller horizontal - * display range. - */ - - devcol = col + UG2864HSWEG01_DEV_XOFFSET; - - /* Lock and select device */ - - ug2864hsweg01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the starting position for the run */ - /* Set the column address to the XOFFSET value */ - - SPI_SEND(priv->spi, SSD1306_SETCOLL(devcol & 0x0f)); - SPI_SEND(priv->spi, SSD1306_SETCOLH(devcol >> 4)); - - /* Set the page address */ - - SPI_SEND(priv->spi, SSD1306_PAGEADDR(page)); - - /* Select data transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, false); - - /* Then transfer all of the data */ - - (void)SPI_SNDBLOCK(priv->spi, fbptr, pixlen); - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864hsweg01_unlock(priv->spi); - return OK; -} -#else -# error "Configuration not implemented" -#endif - -/************************************************************************************** - * Name: ug2864hsweg01_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * Description: - * This method can be used to write a partial raster line to the LCD. - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) -static int ug2864hsweg01_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ - /* Because of this line of code, we will only be able to support a single UG device */ - - FAR struct ug2864hsweg01_dev_s *priv = &g_oleddev; - FAR uint8_t *fbptr; - uint8_t page; - uint8_t fbmask; - uint8_t usrmask; - int pixlen; - uint8_t i; - - lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Clip the run to the display */ - - pixlen = npixels; - if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG2864HSWEG01_XRES) - { - pixlen = (int)UG2864HSWEG01_XRES - (int)col; - } - - /* Verify that some portion of the run is actually the display */ - - if (pixlen <= 0 || row > UG2864HSWEG01_YRES) - { - return -EINVAL; - } - - /* Perform coordinate conversion for reverse landscape mode */ - -#ifdef CONFIG_LCD_RLANDSCAPE - row = (UG2864HSWEG01_YRES-1) - row; - col = (UG2864HSWEG01_XRES-1) - col; -#endif - - /* Then transfer the display data from the shadow frame buffer memory */ - /* Get the page number. The range of 64 lines is divided up into eight - * pages of 8 lines each. - */ - - page = row >> 3; - - /* Update the shadow frame buffer memory. First determine the pixel - * position in the frame buffer memory. Pixels are organized like - * this: - * - * --------+---+---+---+---+-...-+-----+ - * Segment | 0 | 1 | 2 | 3 | ... | 131 | - * --------+---+---+---+---+-...-+-----+ - * D0 | | X | | | | | - * D1 | | X | | | | | - * D2 | | X | | | | | - * D3 | | X | | | | | - * D4 | | X | | | | | - * D5 | | X | | | | | - * D6 | | X | | | | | - * D7 | | X | | | | | - * --------+---+---+---+---+-...-+-----+ - * - * So, in order to draw a white, horizontal line, at row 45. we - * would have to modify all of the bytes in page 45/8 = 5. We - * would have to set bit 45%8 = 5 in every byte in the page. - */ - - fbmask = 1 << (row & 7); -#ifdef CONFIG_LCD_RLANDSCAPE - fbptr = &priv->fb[page * (UG2864HSWEG01_XRES-1) + col + pixlen]; -#else - fbptr = &priv->fb[page * UG2864HSWEG01_XRES + col]; -#endif -#ifdef CONFIG_NX_PACKEDMSFIRST - usrmask = MS_BIT; -#else - usrmask = LS_BIT; -#endif - - *buffer = 0; - for (i = 0; i < pixlen; i++) - { - /* Set or clear the corresponding bit */ - -#ifdef CONFIG_LCD_RLANDSCAPE - uint8_t byte = *fbptr--; -#else - uint8_t byte = *fbptr++; -#endif - if ((byte & fbmask) != 0) - { - *buffer |= usrmask; - } - - /* Inc/Decrement to the next destination pixel. Hmmmm. It looks like - * this logic could write past the end of the user buffer. Revisit - * this! - */ - -#ifdef CONFIG_NX_PACKEDMSFIRST - if (usrmask == LS_BIT) - { - buffer++; - *buffer = 0; - usrmask = MS_BIT; - } - else - { - usrmask >>= 1; - } -#else - if (usrmask == MS_BIT) - { - buffer++; - *buffer = 0; - usrmask = LS_BIT; - } - else - { - usrmask <<= 1; - } -#endif - } - - return OK; -} -#else -# error "Configuration not implemented" -#endif - -/************************************************************************************** - * Name: ug2864hsweg01_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int ug2864hsweg01_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - lcdvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", - g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes); - memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: ug2864hsweg01_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int ug2864hsweg01_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - DEBUGASSERT(pinfo && planeno == 0); - lcdvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp); - memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: ug2864hsweg01_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ug2864hsweg01_getpower(FAR struct lcd_dev_s *dev) -{ - FAR struct ug2864hsweg01_dev_s *priv = (FAR struct ug2864hsweg01_dev_s *)dev; - DEBUGASSERT(priv); - - lcdvdbg("power: %s\n", priv->on ? "ON" : "OFF"); - return priv->on ? CONFIG_LCD_MAXPOWER : 0; -} - -/************************************************************************************** - * Name: ug2864hsweg01_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ug2864hsweg01_setpower(struct lcd_dev_s *dev, int power) -{ - struct ug2864hsweg01_dev_s *priv = (struct ug2864hsweg01_dev_s *)dev; - DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER && priv->spi); - - lcdvdbg("power: %d [%d]\n", power, priv->on ? CONFIG_LCD_MAXPOWER : 0); - - /* Lock and select device */ - - ug2864hsweg01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - if (power <= 0) - { - /* Turn the display off */ - - (void)SPI_SEND(priv->spi, SSD1306_DISPOFF); - priv->on = false; - } - else - { - /* Turn the display on */ - - (void)SPI_SEND(priv->spi, SSD1306_DISPON); /* Display on, dim mode */ - priv->on = true; - } - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864hsweg01_unlock(priv->spi); - return OK; -} - -/************************************************************************************** - * Name: ug2864hsweg01_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ug2864hsweg01_getcontrast(struct lcd_dev_s *dev) -{ - struct ug2864hsweg01_dev_s *priv = (struct ug2864hsweg01_dev_s *)dev; - DEBUGASSERT(priv); - - lcdvdbg("contrast: %d\n", priv->contrast); - return priv->contrast; -} - -/************************************************************************************** - * Name: ug2864hsweg01_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ug2864hsweg01_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) -{ - struct ug2864hsweg01_dev_s *priv = (struct ug2864hsweg01_dev_s *)dev; - unsigned int scaled; - - lcdvdbg("contrast: %d\n", contrast); - DEBUGASSERT(priv); - - /* Verify the contrast value */ - -#ifdef CONFIG_DEBUG - if (contrast > CONFIG_LCD_MAXCONTRAST) - { - return -EINVAL; - } -#endif - - /* Scale contrast: newcontrast = 255 * contrast / CONFIG_LCD_MAXCONTRAST - * Where contrast is in the range {1,255} - */ - -#if CONFIG_LCD_MAXCONTRAST != 255 - scaled = ((contrast << 8) - 1) / CONFIG_LCD_MAXCONTRAST; -#else - scaled = contrast; -#endif - - /* Lock and select device */ - - ug2864hsweg01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the contrast */ - - (void)SPI_SEND(priv->spi, SSD1306_CONTRAST_MODE); /* Set contrast control register */ - (void)SPI_SEND(priv->spi, SSD1306_CONTRAST(scaled)); /* Data 1: Set 1 of 256 contrast steps */ - priv->contrast = contrast; - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864hsweg01_unlock(priv->spi); - return OK; -} - -/************************************************************************************** - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ug2864hsweg01_initialize - * - * Description: - * Initialize the UG-2864HSWEG01 video hardware. The initial state of the - * OLED is fully initialized, display memory cleared, and the OLED ready - * to use, but with the power setting at 0 (full off == sleep mode). - * - * Input Parameters: - * - * spi - A reference to the SPI driver instance. - * devno - A value in the range of 0 through CONFIG_UG2864HSWEG01_NINTERFACES-1. - * This allows support for multiple OLED devices. - * - * Returned Value: - * - * On success, this function returns a reference to the LCD object for - * the specified OLED. NULL is returned on any failure. - * - **************************************************************************************/ - -FAR struct lcd_dev_s *ug2864hsweg01_initialize(FAR struct spi_dev_s *spi, unsigned int devno) -{ - FAR struct ug2864hsweg01_dev_s *priv = &g_oleddev; - - lcdvdbg("Initializing\n"); - DEBUGASSERT(spi && devno == 0); - - /* Save the reference to the SPI device */ - - priv->spi = spi; - - /* Configure the SPI */ - - ug2864hsweg01_configspi(spi); - - /* Lock and select device */ - - ug2864hsweg01_lock(priv->spi); - SPI_SELECT(spi, SPIDEV_DISPLAY, true); - - /* Select command transfer */ - - SPI_CMDDATA(spi, SPIDEV_DISPLAY, true); - - /* Configure OLED SPI or I/O, must be delayed 1-10ms */ - - up_mdelay(5); - - /* Configure the device */ - -//#define OLED_WriteCmd(v) SPI_SEND(spi,v) -// -// /* Module manufacturers to provide initialization code Ä£¿é³§¼ÒÌṩ³õʼ»¯´úÂë */ -// -// OLED_WriteCmd(0xAE); /* ¹Ø±ÕOLEDÃæ°åÏÔʾ(ÐÝÃß) */ -// OLED_WriteCmd(0x00); /* ÉèÖÃÁеØÖ·µÍ4bit */ -// OLED_WriteCmd(0x10); /* ÉèÖÃÁеØÖ·¸ß4bit */ -// OLED_WriteCmd(0x40); /* ÉèÖÃÆðʼÐеØÖ·£¨µÍ5bit 0-63£©£¬ Ó²¼þÏà¹Ø*/ -// -// OLED_WriteCmd(0x81); /* ÉèÖöԱȶÈÃüÁî(Ë«×Ö½ÚÃüÁ£¬µÚ1¸ö×Ö½ÚÊÇÃüÁµÚ2¸ö×Ö½ÚÊǶԱȶȲÎÊý0-255 */ -// OLED_WriteCmd(0xCF); /* ÉèÖöԱȶȲÎÊý */ -// -// OLED_WriteCmd(0xA1); /* A0 £ºÁеØÖ·0Ó³Éäµ½SEG0; A1 £ºÁеØÖ·127Ó³Éäµ½SEG0 */ -// OLED_WriteCmd(0xA6); /* A6 : ÉèÖÃÕý³£ÏÔʾģʽ; A7 : ÉèÖÃΪ·´ÏÔģʽ */ -// -// OLED_WriteCmd(0xA8); /* ÉèÖÃCOM·Êý */ -// OLED_WriteCmd(0x3F); /* 1 ->£¨63+1£©Â· */ -// -// OLED_WriteCmd(0xD3); /* ÉèÖÃÏÔʾƫÒÆ£¨Ë«×Ö½ÚÃüÁ*/ -// OLED_WriteCmd(0x00); /* ÎÞÆ«ÒÆ */ -// -// OLED_WriteCmd(0xD5); /* ÉèÖÃÏÔʾʱÖÓ·ÖƵϵÊý/Õñµ´ÆµÂÊ */ -// OLED_WriteCmd(0x80); /* ÉèÖ÷ÖƵϵÊý,¸ß4bitÊÇ·ÖƵϵÊý£¬µÍ4bitÊÇÕñµ´ÆµÂÊ */ -// -// OLED_WriteCmd(0xD9); /* ÉèÖÃÔ¤³äµçÖÜÆÚ */ -// OLED_WriteCmd(0xF1); /* [3:0],PHASE 1; [7:4],PHASE 2; */ -// -// OLED_WriteCmd(0xDA); /* ÉèÖÃCOM½ÅÓ²¼þ½ÓÏß·½Ê½ */ -// OLED_WriteCmd(0x12); -// -// OLED_WriteCmd(0xDB); /* ÉèÖà vcomh µçѹ±¶ÂÊ */ -// OLED_WriteCmd(0x40); /* [6:4] 000 = 0.65 x VCC; 0.77 x VCC (RESET); 0.83 x VCC */ -// -// OLED_WriteCmd(0x8D); /* ÉèÖóäµç±Ã£¨ºÍϸöÃüÁî½áºÏʹÓã© */ -// OLED_WriteCmd(0x14); /* 0x14 ʹÄܳäµç±Ã£¬ 0x10 ÊÇ¹Ø±Õ */ -// OLED_WriteCmd(0xAF); /* ´ò¿ªOLEDÃæ°å */ - - SPI_SEND(spi, SSD1306_DISPOFF); /* Display off 0xAE*/ - SPI_SEND(spi, SSD1306_SETCOLL(0)); /* Set lower column address 0x00 */ - SPI_SEND(spi, SSD1306_SETCOLH(0)); /* Set higher column address 0x10 */ - SPI_SEND(spi, SSD1306_STARTLINE(0)); /* Set display start line 0x40*/ - /* SPI_SEND(spi, SSD1306_PAGEADDR(0));*//* Set page address (Can ignore)*/ - SPI_SEND(spi, SSD1306_CONTRAST_MODE); /* Contrast control 0x81*/ - SPI_SEND(spi ,SSD1306_CONTRAST(UG2864HSWEG01_CONTRAST)); /* Default contrast 0xCF */ - SPI_SEND(spi, SSD1306_REMAPPLEFT); /* Set segment remap left 95 to 0 | 0xA1*/ - /* SPI_SEND(spi, SSD1306_EDISPOFF); */ /* Normal display :off 0xA4 (Can ignore)*/ - SPI_SEND(spi, SSD1306_NORMAL); /* Normal (un-reversed) display mode 0xA6 */ - SPI_SEND(spi, SSD1306_MRATIO_MODE); /* Multiplex ratio 0xA8*/ - SPI_SEND(spi, SSD1306_MRATIO(0x3f)); /* Duty = 1/64 */ - /* SPI_SEND(spi, SSD1306_SCANTOCOM0);*/ /* Com scan direction: Scan from COM[n-1] to COM[0] (Can ignore)*/ - SPI_SEND(spi, SSD1306_DISPOFFS_MODE); /* Set display offset 0xD3 */ - SPI_SEND(spi, SSD1306_DISPOFFS(0)); - SPI_SEND(spi, SSD1306_CLKDIV_SET); /* Set clock divider 0xD5*/ - SPI_SEND(spi, SSD1306_CLKDIV(8,0)); /* 0x80*/ - - SPI_SEND(spi, SSD1306_CHRGPER_SET); /* ++Set pre-charge period 0xD9*/ - SPI_SEND(spi, SSD1306_CHRGPER(0x0f,1)); /* 0xf1 or 0x22£¨Enhanced mode?£© */ - - SPI_SEND(spi, SSD1306_CMNPAD_CONFIG); /* Set common pads / set com pins hardware configuration 0xDA*/ - SPI_SEND(spi, SSD1306_CMNPAD(0x12)); /* 0x12 */ - - SPI_SEND(spi, SSD1306_VCOM_SET); /* set vcomh 0xDB*/ - SPI_SEND(spi, SSD1306_VCOM(0x40)); - - SPI_SEND(spi, SSD1306_CHRPUMP_SET); /* ++Set Charge Pump enable/disable 0x8D ssd1306*/ - SPI_SEND(spi, SSD1306_CHRPUMP_ON); /* 0x14 close 0x10 */ - - /*SPI_SEND(spi, SSD1306_DCDC_MODE); */ /* DC/DC control mode: on (SSD1306 Not supported) */ - /*SPI_SEND(spi, SSD1306_DCDC_ON); */ - - SPI_SEND(spi, SSD1306_DISPON); /* display ON 0xAF */ - - /* De-select and unlock the device */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, false); - ug2864hsweg01_unlock(priv->spi); - - /* Clear the display */ - - up_mdelay(100); - ug2864hsweg01_fill(&priv->dev, UG_Y1_BLACK); - return &priv->dev; -} - -/************************************************************************************** - * Name: ug2864hsweg01_fill - * - * Description: - * This non-standard method can be used to clear the entire display by writing one - * color to the display. This is much faster than writing a series of runs. - * - * Input Parameters: - * priv - Reference to private driver structure - * - * Assumptions: - * Caller has selected the OLED section. - * - **************************************************************************************/ - -void ug2864hsweg01_fill(FAR struct lcd_dev_s *dev, uint8_t color) -{ - FAR struct ug2864hsweg01_dev_s *priv = &g_oleddev; - unsigned int page; - - /* Make an 8-bit version of the selected color */ - - if (color & 1) - { - color = 0xff; - } - else - { - color = 0; - } - - /* Initialize the framebuffer */ - - memset(priv->fb, color, UG2864HSWEG01_FBSIZE); - - /* Lock and select device */ - - ug2864hsweg01_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, true); - - /* Visit each page */ - - for (page = 0; page < UG2864HSWEG01_DEV_PAGES; page++) - { - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the column address to the XOFFSET value */ - - SPI_SEND(priv->spi, SSD1306_SETCOLL(UG2864HSWEG01_DEV_XOFFSET)); - SPI_SEND(priv->spi, SSD1306_SETCOLH(0)); - - /* Set the page address */ - - SPI_SEND(priv->spi, SSD1306_PAGEADDR(page)); - - /* Select data transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, false); - - /* Transfer one page of the selected color */ - - (void)SPI_SNDBLOCK(priv->spi, &priv->fb[page * UG2864HSWEG01_XRES], - UG2864HSWEG01_XRES); - } - - /* De-select and unlock the device */ - - SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false); - ug2864hsweg01_unlock(priv->spi); -} - -#endif /* CONFIG_LCD_UG2864HSWEG01 */ diff --git a/nuttx/drivers/lcd/ug-9664hswag01.c b/nuttx/drivers/lcd/ug-9664hswag01.c deleted file mode 100644 index 6ef78fca6..000000000 --- a/nuttx/drivers/lcd/ug-9664hswag01.c +++ /dev/null @@ -1,1046 +0,0 @@ -/************************************************************************************** - * drivers/lcd/ug-9664hswag01.c - * Driver for the Univision UG-9664HSWAG01 Display with the Solomon Systech SSD1305 LCD - * controller. - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Reference: "Product Specification, OEL Display Module, UG-9664HSWAG01", Univision - * Technology Inc., SAS1-6020-B, January 3, 2008. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************************/ - -/************************************************************************************** - * Included Files - **************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ssd1305.h" - -/************************************************************************************** - * Pre-processor Definitions - **************************************************************************************/ - -/* Configuration **********************************************************************/ -/* UG-9664HSWAG01 Configuration Settings: - * - * CONFIG_UG9664HSWAG01_SPIMODE - Controls the SPI mode - * CONFIG_UG9664HSWAG01_FREQUENCY - Define to use a different bus frequency - * CONFIG_UG9664HSWAG01_NINTERFACES - Specifies the number of physical - * UG-9664HSWAG01 devices that will be supported. NOTE: At present, this - * must be undefined or defined to be 1. - * CONFIG_UG9664HSWAG01_POWER - * If the hardware supports a controllable OLED a power supply, this - * configuration shold be defined. (See ug_power() below). - * - * Required LCD driver settings: - * CONFIG_LCD_UG9664HSWAG01 - Enable UG-9664HSWAG01 support - * CONFIG_LCD_MAXCONTRAST should be 255, but any value >0 and <=255 will be accepted. - * CONFIG_LCD_MAXPOWER should be 2: 0=off, 1=dim, 2=normal - * - * Required SPI driver settings: - * CONFIG_SPI_CMDDATA - Include support for cmd/data selection. - */ - -/* Verify that all configuration requirements have been met */ - -/* The UG-9664HSWAG01 spec says that is supports SPI mode 0,0 only. However, somtimes - * you need to tinker with these things. - */ - -#ifndef CONFIG_UG9664HSWAG01_SPIMODE -# define CONFIG_UG9664HSWAG01_SPIMODE SPIDEV_MODE0 -#endif - -/* SPI frequency */ - -#ifndef CONFIG_UG9664HSWAG01_FREQUENCY -# define CONFIG_UG9664HSWAG01_FREQUENCY 3500000 -#endif - -/* CONFIG_UG9664HSWAG01_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_UG9664HSWAG01_NINTERFACES -# define CONFIG_UG9664HSWAG01_NINTERFACES 1 -#endif - -#if CONFIG_UG9664HSWAG01_NINTERFACES != 1 -# warning "Only a single UG-9664HSWAG01 interface is supported" -# undef CONFIG_UG9664HSWAG01_NINTERFACES -# define CONFIG_UG9664HSWAG01_NINTERFACES 1 -#endif - -/* Verbose debug must also be enabled to use the extra OLED debug */ - -#ifndef CONFIG_DEBUG -# undef CONFIG_DEBUG_VERBOSE -#endif - -#ifndef CONFIG_DEBUG_VERBOSE -# undef CONFIG_DEBUG_LCD -#endif - -/* Check contrast selection */ - -#ifndef CONFIG_LCD_MAXCONTRAST -# define CONFIG_LCD_MAXCONTRAST 255 -#endif - -#if CONFIG_LCD_MAXCONTRAST <= 0 || CONFIG_LCD_MAXCONTRAST > 255 -# error "CONFIG_LCD_MAXCONTRAST exceeds supported maximum" -#endif - -#if CONFIG_LCD_MAXCONTRAST < 255 -# warning "Optimal setting of CONFIG_LCD_MAXCONTRAST is 255" -#endif - -/* Check power setting */ - -#if !defined(CONFIG_LCD_MAXPOWER) -# define CONFIG_LCD_MAXPOWER 2 -#endif - -#if CONFIG_LCD_MAXPOWER != 2 -# warning "CONFIG_LCD_MAXPOWER should be 2" -# undef CONFIG_LCD_MAXPOWER -# define CONFIG_LCD_MAXPOWER 2 -#endif - -/* The OLED requires CMD/DATA SPI support */ - -#ifndef CONFIG_SPI_CMDDATA -# error "CONFIG_SPI_CMDDATA must be defined in your NuttX configuration" -#endif - -/* Color is 1bpp monochrome with leftmost column contained in bits 0 */ - -#ifdef CONFIG_NX_DISABLE_1BPP -# warning "1 bit-per-pixel support needed" -#endif - -/* Color Properties *******************************************************************/ -/* The SSD1305 display controller can handle a resolution of 132x64. The OLED - * on the base board is 96x64. - */ - -#define UG_DEV_XRES 132 -#define UG_XOFFSET 18 - -/* Display Resolution */ - -#define UG_XRES 96 -#define UG_YRES 64 - -/* Color depth and format */ - -#define UG_BPP 1 -#define UG_COLORFMT FB_FMT_Y1 - -/* Bytes per logical row and actual device row */ - -#define UG_XSTRIDE (UG_XRES >> 3) /* Pixels arrange "horizontally for user" */ -#define UG_YSTRIDE (UG_YRES >> 3) /* But actual device arrangement is "vertical" */ - -/* The size of the shadow frame buffer */ - -#define UG_FBSIZE (UG_XRES * UG_YSTRIDE) - -/* Bit helpers */ - -#define LS_BIT (1 << 0) -#define MS_BIT (1 << 7) - -/* Debug ******************************************************************************/ - -#ifdef CONFIG_DEBUG_LCD -# define lcddbg(format, arg...) vdbg(format, ##arg) -#else -# define lcddbg(x...) -#endif - -/************************************************************************************** - * Private Type Definition - **************************************************************************************/ - -/* This structure describes the state of this driver */ - -struct ug_dev_s -{ - /* Publically visible device structure */ - - struct lcd_dev_s dev; - - /* Private LCD-specific information follows */ - - FAR struct spi_dev_s *spi; - uint8_t contrast; - uint8_t powered; - - /* The SSD1305 does not support reading from the display memory in SPI mode. - * Since there is 1 BPP and access is byte-by-byte, it is necessary to keep - * a shadow copy of the framebuffer memory. - */ - - uint8_t fb[UG_FBSIZE]; -}; - -/************************************************************************************** - * Private Function Protototypes - **************************************************************************************/ - -/* SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ug_select(FAR struct spi_dev_s *spi); -static inline void ug_deselect(FAR struct spi_dev_s *spi); -#else -static void ug_select(FAR struct spi_dev_s *spi); -static void ug_deselect(FAR struct spi_dev_s *spi); -#endif - -/* LCD Data Transfer Methods */ - -static int ug_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels); -static int ug_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels); - -/* LCD Configuration */ - -static int ug_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo); -static int ug_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo); - -/* LCD RGB Mapping */ - -#ifdef CONFIG_FB_CMAP -# error "RGB color mapping not supported by this driver" -#endif - -/* Cursor Controls */ - -#ifdef CONFIG_FB_HWCURSOR -# error "Cursor control not supported by this driver" -#endif - -/* LCD Specific Controls */ - -static int ug_getpower(struct lcd_dev_s *dev); -static int ug_setpower(struct lcd_dev_s *dev, int power); -static int ug_getcontrast(struct lcd_dev_s *dev); -static int ug_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); - -/* Initialization */ - -static inline void up_clear(FAR struct ug_dev_s *priv); - -/************************************************************************************** - * Private Data - **************************************************************************************/ - -/* This is working memory allocated by the LCD driver for each LCD device - * and for each color plane. This memory will hold one raster line of data. - * The size of the allocated run buffer must therefore be at least - * (bpp * xres / 8). Actual alignment of the buffer must conform to the - * bitwidth of the underlying pixel type. - * - * If there are multiple planes, they may share the same working buffer - * because different planes will not be operate on concurrently. However, - * if there are multiple LCD devices, they must each have unique run buffers. - */ - -static uint8_t g_runbuffer[UG_XSTRIDE+1]; - -/* This structure describes the overall LCD video controller */ - -static const struct fb_videoinfo_s g_videoinfo = -{ - .fmt = UG_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ - .xres = UG_XRES, /* Horizontal resolution in pixel columns */ - .yres = UG_YRES, /* Vertical resolution in pixel rows */ - .nplanes = 1, /* Number of color planes supported */ -}; - -/* This is the standard, NuttX Plane information object */ - -static const struct lcd_planeinfo_s g_planeinfo = -{ - .putrun = ug_putrun, /* Put a run into LCD memory */ - .getrun = ug_getrun, /* Get a run from LCD memory */ - .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */ - .bpp = UG_BPP, /* Bits-per-pixel */ -}; - -/* This is the standard, NuttX LCD driver object */ - -static struct ug_dev_s g_ugdev = -{ - .dev = - { - /* LCD Configuration */ - - .getvideoinfo = ug_getvideoinfo, - .getplaneinfo = ug_getplaneinfo, - - /* LCD RGB Mapping -- Not supported */ - /* Cursor Controls -- Not supported */ - - /* LCD Specific Controls */ - - .getpower = ug_getpower, - .setpower = ug_setpower, - .getcontrast = ug_getcontrast, - .setcontrast = ug_setcontrast, - }, -}; - -/************************************************************************************** - * Private Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ug_powerstring - * - * Description: - * Convert the power setting to a string. - * - **************************************************************************************/ - - -static inline FAR const char *ug_powerstring(uint8_t power) -{ - if (power == UG_POWER_OFF) - { - return "OFF"; - } - else if (power == UG_POWER_DIM) - { - return "DIM"; - } - else if (power == UG_POWER_ON) - { - return "ON"; - } - else - { - return "ERROR"; - } -} - -/************************************************************************************** - * Function: ug_select - * - * Description: - * Select the SPI, locking and re-configuring if necessary - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ug_select(FAR struct spi_dev_s *spi) -{ - /* We own the SPI bus, so just select the chip */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, true); -} -#else -static void ug_select(FAR struct spi_dev_s *spi) -{ - /* Select UG-9664HSWAG01 chip (locking the SPI bus in case there are multiple - * devices competing for the SPI bus - */ - - SPI_LOCK(spi, true); - SPI_SELECT(spi, SPIDEV_DISPLAY, true); - - /* Now make sure that the SPI bus is configured for the UG-9664HSWAG01 (it - * might have gotten configured for a different device while unlocked) - */ - - SPI_SETMODE(spi, CONFIG_UG9664HSWAG01_SPIMODE); - SPI_SETBITS(spi, 8); -#ifdef CONFIG_UG9664HSWAG01_FREQUENCY - SPI_SETFREQUENCY(spi, CONFIG_UG9664HSWAG01_FREQUENCY); -#endif -} -#endif - -/************************************************************************************** - * Function: ug_deselect - * - * Description: - * De-select the SPI - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - **************************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ug_deselect(FAR struct spi_dev_s *spi) -{ - /* We own the SPI bus, so just de-select the chip */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, false); -} -#else -static void ug_deselect(FAR struct spi_dev_s *spi) -{ - /* De-select UG-9664HSWAG01 chip and relinquish the SPI bus. */ - - SPI_SELECT(spi, SPIDEV_DISPLAY, false); - SPI_LOCK(spi, false); -} -#endif - -/************************************************************************************** - * Name: ug_putrun - * - * Description: - * This method can be used to write a partial raster line to the LCD: - * - * row - Starting row to write to (range: 0 <= row < yres) - * col - Starting column to write to (range: 0 <= col <= xres-npixels) - * buffer - The buffer containing the run to be written to the LCD - * npixels - The number of pixels to write to the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int ug_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, - size_t npixels) -{ - /* Because of this line of code, we will only be able to support a single UG device */ - - FAR struct ug_dev_s *priv = &g_ugdev; - FAR uint8_t *fbptr; - FAR uint8_t *ptr; - uint8_t devcol; - uint8_t fbmask; - uint8_t page; - uint8_t usrmask; - uint8_t i; - int pixlen; - - gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Clip the run to the display */ - - pixlen = npixels; - if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG_XRES) - { - pixlen = (int)UG_XRES - (int)col; - } - - /* Verify that some portion of the run remains on the display */ - - if (pixlen <= 0 || row > UG_YRES) - { - return OK; - } - - /* Get the page number. The range of 64 lines is divided up into eight - * pages of 8 lines each. - */ - - page = row >> 3; - - /* Update the shadow frame buffer memory. First determine the pixel - * position in the frame buffer memory. Pixels are organized like - * this: - * - * --------+---+---+---+---+-...-+-----+ - * Segment | 0 | 1 | 2 | 3 | ... | 131 | - * --------+---+---+---+---+-...-+-----+ - * Bit 0 | | X | | | | | - * Bit 1 | | X | | | | | - * Bit 2 | | X | | | | | - * Bit 3 | | X | | | | | - * Bit 4 | | X | | | | | - * Bit 5 | | X | | | | | - * Bit 6 | | X | | | | | - * Bit 7 | | X | | | | | - * --------+---+---+---+---+-...-+-----+ - * - * So, in order to draw a white, horizontal line, at row 45. we - * would have to modify all of the bytes in page 45/8 = 5. We - * would have to set bit 45%8 = 5 in every byte in the page. - */ - - fbmask = 1 << (row & 7); - fbptr = &priv->fb[page * UG_XRES + col]; - ptr = fbptr; -#ifdef CONFIG_NX_PACKEDMSFIRST - usrmask = MS_BIT; -#else - usrmask = LS_BIT; -#endif - - for (i = 0; i < pixlen; i++) - { - /* Set or clear the corresponding bit */ - - if ((*buffer & usrmask) != 0) - { - *ptr++ |= fbmask; - } - else - { - *ptr++ &= ~fbmask; - } - - /* Inc/Decrement to the next source pixel */ - -#ifdef CONFIG_NX_PACKEDMSFIRST - if (usrmask == LS_BIT) - { - buffer++; - usrmask = MS_BIT; - } - else - { - usrmask >>= 1; - } -#else - if (usrmask == MS_BIT) - { - buffer++; - usrmask = LS_BIT; - } - else - { - usrmask <<= 1; - } -#endif - } - - /* Offset the column position to account for smaller horizontal - * display range. - */ - - devcol = col + UG_XOFFSET; - - /* Select and lock the device */ - - ug_select(priv->spi); - - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the starting position for the run */ - - (void)SPI_SEND(priv->spi, SSD1305_SETPAGESTART+page); /* Set the page start */ - (void)SPI_SEND(priv->spi, SSD1305_SETCOLL + (devcol & 0x0f)); /* Set the low column */ - (void)SPI_SEND(priv->spi, SSD1305_SETCOLH + (devcol >> 4)); /* Set the high column */ - - /* Select data transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, false); - - /* Then transfer all of the data */ - - (void)SPI_SNDBLOCK(priv->spi, fbptr, pixlen); - - /* Unlock and de-select the device */ - - ug_deselect(priv->spi); - return OK; -} - -/************************************************************************************** - * Name: ug_getrun - * - * Description: - * This method can be used to read a partial raster line from the LCD: - * - * row - Starting row to read from (range: 0 <= row < yres) - * col - Starting column to read read (range: 0 <= col <= xres-npixels) - * buffer - The buffer in which to return the run read from the LCD - * npixels - The number of pixels to read from the LCD - * (range: 0 < npixels <= xres-col) - * - **************************************************************************************/ - -static int ug_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, - size_t npixels) -{ - /* Because of this line of code, we will only be able to support a single UG device */ - - FAR struct ug_dev_s *priv = &g_ugdev; - FAR uint8_t *fbptr; - uint8_t page; - uint8_t fbmask; - uint8_t usrmask; - uint8_t i; - int pixlen; - - gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); - DEBUGASSERT(buffer); - - /* Clip the run to the display */ - - pixlen = npixels; - if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG_XRES) - { - pixlen = (int)UG_XRES - (int)col; - } - - /* Verify that some portion of the run is actually the display */ - - if (pixlen <= 0 || row > UG_YRES) - { - return -EINVAL; - } - - /* Then transfer the display data from the shadow frame buffer memory */ - /* Get the page number. The range of 64 lines is divided up into eight - * pages of 8 lines each. - */ - - page = row >> 3; - - /* Update the shadow frame buffer memory. First determine the pixel - * position in the frame buffer memory. Pixels are organized like - * this: - * - * --------+---+---+---+---+-...-+-----+ - * Segment | 0 | 1 | 2 | 3 | ... | 131 | - * --------+---+---+---+---+-...-+-----+ - * Bit 0 | | X | | | | | - * Bit 1 | | X | | | | | - * Bit 2 | | X | | | | | - * Bit 3 | | X | | | | | - * Bit 4 | | X | | | | | - * Bit 5 | | X | | | | | - * Bit 6 | | X | | | | | - * Bit 7 | | X | | | | | - * --------+---+---+---+---+-...-+-----+ - * - * So, in order to draw a white, horizontal line, at row 45. we - * would have to modify all of the bytes in page 45/8 = 5. We - * would have to set bit 45%8 = 5 in every byte in the page. - */ - - fbmask = 1 << (row & 7); - fbptr = &priv->fb[page * UG_XRES + col]; -#ifdef CONFIG_NX_PACKEDMSFIRST - usrmask = MS_BIT; -#else - usrmask = LS_BIT; -#endif - - *buffer = 0; - for (i = 0; i < pixlen; i++) - { - /* Set or clear the corresponding bit */ - - uint8_t byte = *fbptr++; - if ((byte & fbmask) != 0) - { - *buffer |= usrmask; - } - - /* Inc/Decrement to the next destination pixel. Hmmmm. It looks like - * this logic could write past the end of the user buffer. Revisit - * this! - */ - -#ifdef CONFIG_NX_PACKEDMSFIRST - if (usrmask == LS_BIT) - { - buffer++; - *buffer = 0; - usrmask = MS_BIT; - } - else - { - usrmask >>= 1; - } -#else - if (usrmask == MS_BIT) - { - buffer++; - *buffer = 0; - usrmask = LS_BIT; - } - else - { - usrmask <<= 1; - } -#endif - } - - return OK; -} - -/************************************************************************************** - * Name: ug_getvideoinfo - * - * Description: - * Get information about the LCD video controller configuration. - * - **************************************************************************************/ - -static int ug_getvideoinfo(FAR struct lcd_dev_s *dev, - FAR struct fb_videoinfo_s *vinfo) -{ - DEBUGASSERT(dev && vinfo); - gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", - g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes); - memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: ug_getplaneinfo - * - * Description: - * Get information about the configuration of each LCD color plane. - * - **************************************************************************************/ - -static int ug_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, - FAR struct lcd_planeinfo_s *pinfo) -{ - DEBUGASSERT(dev && pinfo && planeno == 0); - gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp); - memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s)); - return OK; -} - -/************************************************************************************** - * Name: ug_getpower - * - * Description: - * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ug_getpower(struct lcd_dev_s *dev) -{ - struct ug_dev_s *priv = (struct ug_dev_s *)dev; - DEBUGASSERT(priv); - gvdbg("powered: %s\n", ug_powerstring(priv->powered)); - return priv->powered; -} - -/************************************************************************************** - * Name: ug_setpower - * - * Description: - * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On - * backlit LCDs, this setting may correspond to the backlight setting. - * - **************************************************************************************/ - -static int ug_setpower(struct lcd_dev_s *dev, int power) -{ - struct ug_dev_s *priv = (struct ug_dev_s *)dev; - - DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER); - gvdbg("power: %s powered: %s\n", - ug_powerstring(power), ug_powerstring(priv->powered)); - - /* Select and lock the device */ - - ug_select(priv->spi); - if (power <= UG_POWER_OFF) - { - /* Turn the display off */ - - (void)SPI_SEND(priv->spi, SSD1305_DISPOFF); /* Display off */ - - /* Remove power to the device */ - - ug_power(0, false); - priv->powered = UG_POWER_OFF; - } - else - { - /* Turn the display on, dim or normal */ - - if (power == UG_POWER_DIM) - { - (void)SPI_SEND(priv->spi, SSD1305_DISPONDIM); /* Display on, dim mode */ - } - else /* if (power > UG_POWER_DIM) */ - { - (void)SPI_SEND(priv->spi, SSD1305_DISPON); /* Display on, normal mode */ - power = UG_POWER_ON; - } - (void)SPI_SEND(priv->spi, SSD1305_DISPRAM); /* Resume to RAM content display */ - - /* Restore power to the device */ - - ug_power(0, true); - priv->powered = power; - } - ug_deselect(priv->spi); - - return OK; -} - -/************************************************************************************** - * Name: ug_getcontrast - * - * Description: - * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ug_getcontrast(struct lcd_dev_s *dev) -{ - struct ug_dev_s *priv = (struct ug_dev_s *)dev; - DEBUGASSERT(priv); - return (int)priv->contrast; -} - -/************************************************************************************** - * Name: ug_setcontrast - * - * Description: - * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). - * - **************************************************************************************/ - -static int ug_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) -{ - struct ug_dev_s *priv = (struct ug_dev_s *)dev; - - gvdbg("contrast: %d\n", contrast); - DEBUGASSERT(priv); - - if (contrast > 255) - { - return -EINVAL; - } - - /* Select and lock the device */ - - ug_select(priv->spi); - - /* Select command transfer */ - - SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); - - /* Set the contrast */ - - (void)SPI_SEND(priv->spi, SSD1305_SETCONTRAST); /* Set contrast control register */ - (void)SPI_SEND(priv->spi, contrast); /* Data 1: Set 1 of 256 contrast steps */ - priv->contrast = contrast; - - /* Unlock and de-select the device */ - - ug_deselect(priv->spi); - return OK; -} - -/************************************************************************************** - * Name: up_clear - * - * Description: - * Clear the display. - * - **************************************************************************************/ - -static inline void up_clear(FAR struct ug_dev_s *priv) -{ - FAR struct spi_dev_s *spi = priv->spi; - int page; - int i; - - /* Clear the framebuffer */ - - memset(priv->fb, UG_Y1_BLACK, UG_FBSIZE); - - /* Select and lock the device */ - - ug_select(priv->spi); - - /* Go through all 8 pages */ - - for (page = 0, i = 0; i < 8; i++) - { - /* Select command transfer */ - - SPI_CMDDATA(spi, SPIDEV_DISPLAY, true); - - /* Set the starting position for the run */ - - (void)SPI_SEND(priv->spi, SSD1305_SETPAGESTART+i); - (void)SPI_SEND(priv->spi, SSD1305_SETCOLL + (UG_XOFFSET & 0x0f)); - (void)SPI_SEND(priv->spi, SSD1305_SETCOLH + (UG_XOFFSET >> 4)); - - /* Select data transfer */ - - SPI_CMDDATA(spi, SPIDEV_DISPLAY, false); - - /* Then transfer all 96 columns of data */ - - (void)SPI_SNDBLOCK(priv->spi, &priv->fb[page * UG_XRES], UG_XRES); - } - - /* Unlock and de-select the device */ - - ug_deselect(spi); -} - -/************************************************************************************** - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ug_initialize - * - * Description: - * Initialize the UG-9664HSWAG01 video hardware. The initial state of the - * OLED is fully initialized, display memory cleared, and the OLED ready to - * use, but with the power setting at 0 (full off == sleep mode). - * - * Input Parameters: - * - * spi - A reference to the SPI driver instance. - * devno - A value in the range of 0 through CONFIG_UG9664HSWAG01_NINTERFACES-1. - * This allows support for multiple OLED devices. - * - * Returned Value: - * - * On success, this function returns a reference to the LCD object for the specified - * OLED. NULL is returned on any failure. - * - **************************************************************************************/ - -FAR struct lcd_dev_s *ug_initialize(FAR struct spi_dev_s *spi, unsigned int devno) -{ - /* Configure and enable LCD */ - - FAR struct ug_dev_s *priv = &g_ugdev; - - gvdbg("Initializing\n"); - DEBUGASSERT(spi && devno == 0); - - /* Save the reference to the SPI device */ - - priv->spi = spi; - - /* Select and lock the device */ - - ug_select(spi); - - /* Make sure that the OLED off */ - - ug_power(0, false); - - /* Select command transfer */ - - SPI_CMDDATA(spi, SPIDEV_DISPLAY, true); - - /* Configure the device */ - - (void)SPI_SEND(spi, SSD1305_SETCOLL + 2); /* Set low column address */ - (void)SPI_SEND(spi, SSD1305_SETCOLH + 2); /* Set high column address */ - (void)SPI_SEND(spi, SSD1305_SETSTARTLINE+0); /* Display start set */ - (void)SPI_SEND(spi, SSD1305_SCROLL_STOP); /* Stop horizontal scroll */ - (void)SPI_SEND(spi, SSD1305_SETCONTRAST); /* Set contrast control register */ - (void)SPI_SEND(spi, 0x32); /* Data 1: Set 1 of 256 contrast steps */ - (void)SPI_SEND(spi, SSD1305_SETBRIGHTNESS); /* Brightness for color bank */ - (void)SPI_SEND(spi, 0x80); /* Data 1: Set 1 of 256 contrast steps */ - (void)SPI_SEND(spi, SSD1305_MAPCOL131); /* Set segment re-map */ - (void)SPI_SEND(spi, SSD1305_DISPNORMAL); /* Set normal display */ -/*(void)SPI_SEND(spi, SSD1305_DISPINVERTED); Set inverse display */ - (void)SPI_SEND(spi, SSD1305_SETMUX); /* Set multiplex ratio */ - (void)SPI_SEND(spi, 0x3f); /* Data 1: MUX ratio -1: 15-63 */ - (void)SPI_SEND(spi, SSD1305_SETOFFSET); /* Set display offset */ - (void)SPI_SEND(spi, 0x40); /* Data 1: Vertical shift by COM: 0-63 */ - (void)SPI_SEND(spi, SSD1305_MSTRCONFIG); /* Set dc-dc on/off */ - (void)SPI_SEND(spi, SSD1305_MSTRCONFIG_EXTVCC); /* Data 1: Select external Vcc */ - (void)SPI_SEND(spi, SSD1305_SETCOMREMAPPED); /* Set com output scan direction */ - (void)SPI_SEND(spi, SSD1305_SETDCLK); /* Set display clock divide - * ratio/oscillator/frequency */ - (void)SPI_SEND(spi, 15 << SSD1305_DCLKFREQ_SHIFT | 0 << SSD1305_DCLKDIV_SHIFT); - (void)SPI_SEND(spi, SSD1305_SETCOLORMODE); /* Set area color mode on/off & low power - * display mode */ - (void)SPI_SEND(spi, SSD1305_COLORMODE_MONO | SSD1305_POWERMODE_LOW); - (void)SPI_SEND(spi, SSD1305_SETPRECHARGE); /* Set pre-charge period */ - (void)SPI_SEND(spi, 15 << SSD1305_PHASE2_SHIFT | 1 << SSD1305_PHASE1_SHIFT); - (void)SPI_SEND(spi, SSD1305_SETCOMCONFIG); /* Set COM configuration */ - (void)SPI_SEND(spi, SSD1305_COMCONFIG_ALT); /* Data 1, Bit 4: 1=Alternative COM pin configuration */ - (void)SPI_SEND(spi, SSD1305_SETVCOMHDESEL); /* Set VCOMH deselect level */ - (void)SPI_SEND(spi, SSD1305_VCOMH_x7p7); /* Data 1: ~0.77 x Vcc */ - (void)SPI_SEND(spi, SSD1305_SETLUT); /* Set look up table for area color */ - (void)SPI_SEND(spi, 0x3f); /* Data 1: Pulse width: 31-63 */ - (void)SPI_SEND(spi, 0x3f); /* Data 2: Color A: 31-63 */ - (void)SPI_SEND(spi, 0x3f); /* Data 3: Color B: 31-63 */ - (void)SPI_SEND(spi, 0x3f); /* Data 4: Color C: 31-63 */ - (void)SPI_SEND(spi, SSD1305_DISPON); /* Display on, normal mode */ - (void)SPI_SEND(spi, SSD1305_DISPRAM); /* Resume to RAM content display */ - - /* Let go of the SPI lock and de-select the device */ - - ug_deselect(spi); - - /* Clear the framebuffer */ - - up_mdelay(100); - up_clear(priv); - return &priv->dev; -} diff --git a/nuttx/drivers/loop.c b/nuttx/drivers/loop.c deleted file mode 100644 index 4744ae0dd..000000000 --- a/nuttx/drivers/loop.c +++ /dev/null @@ -1,509 +0,0 @@ -/**************************************************************************** - * drivers/loop.c - * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define loop_semgive(d) sem_post(&(d)->sem) /* To match loop_semtake */ -#define MAX_OPENCNT (255) /* Limit of uint8_t */ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct loop_struct_s -{ - sem_t sem; /* For safe read-modify-write operations */ - uint32_t nsectors; /* Number of sectors on device */ - off_t offset; /* Offset (in bytes) to the first sector */ - uint16_t sectsize; /* The size of one sector */ - uint8_t opencnt; /* Count of open references to the loop device */ -#ifdef CONFIG_FS_WRITABLE - bool writeenabled; /* true: can write to device */ -#endif - int fd; /* Descriptor of char device/file */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void loop_semtake(FAR struct loop_struct_s *dev); -static int loop_open(FAR struct inode *inode); -static int loop_close(FAR struct inode *inode); -static ssize_t loop_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors); -#ifdef CONFIG_FS_WRITABLE -static ssize_t loop_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, unsigned int nsectors); -#endif -static int loop_geometry(FAR struct inode *inode, struct geometry *geometry); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct block_operations g_bops = -{ - loop_open, /* open */ - loop_close, /* close */ - loop_read, /* read */ -#ifdef CONFIG_FS_WRITABLE - loop_write, /* write */ -#else - NULL, /* write */ -#endif - loop_geometry, /* geometry */ - NULL /* ioctl */ -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: loop_semtake - ****************************************************************************/ - -static void loop_semtake(FAR struct loop_struct_s *dev) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(&dev->sem) != 0) - { - /* The only case that an error should occur here is if - * the wait was awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -/**************************************************************************** - * Name: loop_open - * - * Description: Open the block device - * - ****************************************************************************/ - -static int loop_open(FAR struct inode *inode) -{ - FAR struct loop_struct_s *dev; - int ret = OK; - - DEBUGASSERT(inode && inode->i_private); - dev = (FAR struct loop_struct_s *)inode->i_private; - - /* Make sure we have exclusive access to the state structure */ - - loop_semtake(dev); - if (dev->opencnt == MAX_OPENCNT) - { - return -EMFILE; - } - else - { - /* Increment the open count */ - - dev->opencnt++; - } - - loop_semgive(dev); - return ret; -} - -/**************************************************************************** - * Name: loop_close - * - * Description: close the block device - * - ****************************************************************************/ - -static int loop_close(FAR struct inode *inode) -{ - FAR struct loop_struct_s *dev; - int ret = OK; - - DEBUGASSERT(inode && inode->i_private); - dev = (FAR struct loop_struct_s *)inode->i_private; - - /* Make sure we have exclusive access to the state structure */ - - loop_semtake(dev); - if (dev->opencnt == 0) - { - return -EIO; - } - else - { - /* Decrement the open count */ - - dev->opencnt--; - } - - loop_semgive(dev); - return ret; -} - -/**************************************************************************** - * Name: loop_read - * - * Description: Read the specified numer of sectors - * - ****************************************************************************/ - -static ssize_t loop_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - FAR struct loop_struct_s *dev; - ssize_t nbytesread; - off_t offset; - int ret; - - DEBUGASSERT(inode && inode->i_private); - dev = (FAR struct loop_struct_s *)inode->i_private; - - if (start_sector + nsectors > dev->nsectors) - { - dbg("Read past end of file\n"); - return -EIO; - } - - /* Calculate the offset to read the sectors and seek to the position */ - - offset = start_sector * dev->sectsize + dev->offset; - ret = lseek(dev->fd, offset, SEEK_SET); - if (ret == (off_t)-1) - { - dbg("Seek failed for offset=%d: %d\n", (int)offset, errno); - return -EIO; - } - - /* Then read the requested number of sectors from that position */ - - do - { - nbytesread = read(dev->fd, buffer, nsectors * dev->sectsize); - if (nbytesread < 0 && errno != EINTR) - { - dbg("Read failed: %d\n", errno); - return -errno; - } - } - while (nbytesread < 0); - - /* Return the number of sectors read */ - - return nbytesread / dev->sectsize; -} - -/**************************************************************************** - * Name: loop_write - * - * Description: Write the specified number of sectors - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static ssize_t loop_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - FAR struct loop_struct_s *dev; - ssize_t nbyteswritten; - off_t offset; - int ret; - - DEBUGASSERT(inode && inode->i_private); - dev = (FAR struct loop_struct_s *)inode->i_private; - - /* Calculate the offset to write the sectors and seek to the position */ - - offset = start_sector * dev->sectsize + dev->offset; - ret = lseek(dev->fd, offset, SEEK_SET); - if (ret == (off_t)-1) - { - dbg("Seek failed for offset=%d: %d\n", (int)offset, errno); - } - - /* Then write the requested number of sectors to that position */ - - do - { - nbyteswritten = write(dev->fd, buffer, nsectors * dev->sectsize); - if (nbyteswritten < 0 && errno != EINTR) - { - dbg("Write failed: %d\n", errno); - return -errno; - } - } - while (nbyteswritten < 0); - - /* Return the number of sectors written */ - - return nbyteswritten / dev->sectsize; -} -#endif - -/**************************************************************************** - * Name: loop_geometry - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int loop_geometry(FAR struct inode *inode, struct geometry *geometry) -{ - FAR struct loop_struct_s *dev; - - DEBUGASSERT(inode); - if (geometry) - { - dev = (FAR struct loop_struct_s *)inode->i_private; - geometry->geo_available = true; - geometry->geo_mediachanged = false; -#ifdef CONFIG_FS_WRITABLE - geometry->geo_writeenabled = dev->writeenabled; -#else - geometry->geo_writeenabled = false; -#endif - geometry->geo_nsectors = dev->nsectors; - geometry->geo_sectorsize = dev->sectsize; - return OK; - } - - return -EINVAL; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: losetup - * - * Description: - * Setup the loop device so that it exports the file referenced by 'filename' - * as a block device. - * - ****************************************************************************/ - -int losetup(const char *devname, const char *filename, uint16_t sectsize, - off_t offset, bool readonly) -{ - FAR struct loop_struct_s *dev; - struct stat sb; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!devname || !filename || !sectsize) - { - return -EINVAL; - } -#endif - - /* Get the size of the file */ - - ret = stat(filename, &sb); - if (ret < 0) - { - dbg("Failed to stat %s: %d\n", filename, errno); - return -errno; - } - - /* Check if the file system is big enough for one block */ - - if (sb.st_size - offset < sectsize) - { - dbg("File is too small for blocksize\n"); - return -ERANGE; - } - - /* Allocate a loop device structure */ - - dev = (FAR struct loop_struct_s *)kzalloc(sizeof(struct loop_struct_s)); - if (!dev) - { - return -ENOMEM; - } - - /* Initialize the loop device structure. */ - - sem_init(&dev->sem, 0, 1); - dev->nsectors = (sb.st_size - offset) / sectsize; - dev->sectsize = sectsize; - dev->offset = offset; - - /* Open the file. */ - -#ifdef CONFIG_FS_WRITABLE - dev->writeenabled = false; /* Assume failure */ - dev->fd = -1; - - /* First try to open the device R/W access (unless we are asked - * to open it readonly). - */ - - if (!readonly) - { - dev->fd = open(filename, O_RDWR); - } - - if (dev->fd >= 0) - { - dev->writeenabled = true; /* Success */ - } - else -#endif - { - /* If that fails, then try to open the device read-only */ - - dev->fd = open(filename, O_RDWR); - if (dev->fd < 0) - { - dbg("Failed to open %s: %d\n", filename, errno); - ret = -errno; - goto errout_with_dev; - } - } - - /* Inode private data will be reference to the loop device structure */ - - ret = register_blockdriver(devname, &g_bops, 0, dev); - if (ret < 0) - { - fdbg("register_blockdriver failed: %d\n", -ret); - goto errout_with_fd; - } - - return OK; - -errout_with_fd: - close(dev->fd); -errout_with_dev: - kfree(dev); - return ret; -} - -/**************************************************************************** - * Name: loteardown - * - * Description: - * Undo the setup performed by losetup - * - ****************************************************************************/ - -int loteardown(const char *devname) -{ - FAR struct loop_struct_s *dev; - FAR struct inode *inode; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!devname) - { - return -EINVAL; - } -#endif - - /* Open the block driver associated with devname so that we can get the inode - * reference. - */ - - ret = open_blockdriver(devname, MS_RDONLY, &inode); - if (ret < 0) - { - dbg("Failed to open %s: %d\n", devname, -ret); - return ret; - } - - /* Inode private data is a reference to the loop device stgructure */ - - dev = (FAR struct loop_struct_s *)inode->i_private; - close_blockdriver(inode); - - DEBUGASSERT(dev); - - /* Are there still open references to the device */ - - if (dev->opencnt > 0) - { - return -EBUSY; - } - - /* Otherwise, unregister the block device */ - - ret = unregister_blockdriver(devname); - - /* Release the device structure */ - - if (dev->fd >= 0) - { - (void)close(dev->fd); - } - - kfree(dev); - return ret; -} diff --git a/nuttx/drivers/mmcsd/Kconfig b/nuttx/drivers/mmcsd/Kconfig deleted file mode 100644 index 2d9a04bbb..000000000 --- a/nuttx/drivers/mmcsd/Kconfig +++ /dev/null @@ -1,79 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config MMCSD_NSLOTS - int "Number of MMC/SD slots" - default 1 - ---help--- - Number of MMC/SD slots supported by the - driver. Default is one. - -config MMCSD_READONLY - bool "Disable MMC/SD write access" - default n - ---help--- - Provide read-only access. Default is - Read/Write - -config MMCSD_MULTIBLOCK_DISABLE - bool "Disable MMC/SD multiblock transfer" - default n - ---help--- - Use only the single block transfer method. - This setting is used to work around buggy SDIO drivers that cannot handle - multiple block transfers. - -config MMCSD_MMCSUPPORT - bool "MMC cards support" - default y - ---help--- - Enable support for MMC cards - -config MMCSD_HAVECARDDETECT - bool "MMC/SD card detection" - default y - ---help--- - SDIO driver card detection is - 100% accurate - -config MMCSD_SPI - bool "MMC/SD SPI transfer support" - default y - depends on SPI - -config MMCSD_SPICLOCK - int "MMC/SD maximum SPI clock" - default 20000000 - depends on MMCSD_SPI - ---help--- - Maximum SPI clock to drive MMC/SD card. - Default is 20MHz. - -config MMCSD_SDIO - bool "MMC/SD sdio transfer support" - default n - -if MMCSD_SDIO -config SDIO_DMA - bool "SDIO dma support" - default n - ---help--- - SDIO driver supports DMA - -config SDIO_MUXBUS - bool "SDIO bus share support" - default n - ---help--- - Set this SDIO interface if the SDIO interface - or hardware resources are shared with other drivers. - -config SDIO_WIDTH_D1_ONLY - bool "SDIO 1-bit transfer" - default n - ---help--- - Select 1-bit transfer mode. Default: - 4-bit transfer mode. -endif - diff --git a/nuttx/drivers/mmcsd/Make.defs b/nuttx/drivers/mmcsd/Make.defs deleted file mode 100644 index 06e689c75..000000000 --- a/nuttx/drivers/mmcsd/Make.defs +++ /dev/null @@ -1,56 +0,0 @@ -############################################################################ -# drivers/mmcsd/Make.defs -# -# Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -ifeq ($(CONFIG_MMCSD),y) - -# Include MMC/SD drivers - -ifeq ($(CONFIG_MMCSD_SDIO),y) -CSRCS += mmcsd_sdio.c -endif - -ifeq ($(CONFIG_MMCSD_SPI),y) -CSRCS += mmcsd_spi.c mmcsd_debug.c -endif - -# Include MMC/SD driver build support - -DEPPATH += --dep-path mmcsd -VPATH += :mmcsd -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)mmcsd} - -endif - - diff --git a/nuttx/drivers/mmcsd/mmcsd_csd.h b/nuttx/drivers/mmcsd/mmcsd_csd.h deleted file mode 100644 index d5343aa84..000000000 --- a/nuttx/drivers/mmcsd/mmcsd_csd.h +++ /dev/null @@ -1,424 +0,0 @@ -/**************************************************************************** - * drivers/mmcsd/mmcsd_csd.h - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_MMCSD_MMCSD_CSD_H -#define __DRIVERS_MMCSD_MMCSD_CSD_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include - -/**************************************************************************** - * Pre-Processor Definitions - ****************************************************************************/ - -/* CSD **********************************************************************/ - -/* The CSD is a 16 byte, / 128-bit packed structure. The following macros - * can be used to extract each packed field from the CSD. Two types of - * macros are supported, selected by CONFIG_MMCSD_BE16: (1) byte data (with - * MS byte first), or (2) 16-bit big-endian data (with MS hword first). - */ - -#ifdef CONFIG_MMCSD_BE16 - -/* CSD_STRUCTURE 126-127 */ - -#define MMCSD_CSD_CSDSTRUCT(csd) (csd[0] >> 14) - -/* SPEC_VERS 122-125 = (word 0, bits 13:10) (MMC) Spec version */ - -#define MMC_CSD_SPECVERS(csd) ((csd[0] >> 10) & 0x0f) - -/* Reserved 120-125 */ - -/* TAAC 112-119 = Data read access-time-1 - * TIME_VALUE 3-6 = Time mantissa - * TIME_UNIT 0-2 = Time exponent - */ - -#define MMCSD_CSD_TAAC_TIMEVALUE(csd) ((csd[0] >> 3) & 0x0f) -#define MMCSD_CSD_TAAC_TIMEUNIT(csd) (csd[0] & 7) - -/* NSAC 111:104 = Data read access-time-2 in CLK cycle(NSAC*100) */ - -#define MMCSD_CSD_NSAC(csd) (csd[1] >> 8) - -/* TRAN_SPEED 96-103 = Max. data transfer rate - * TIME_VALUE 3-6 = Rate exponent - * TRANSFER_RATE_UNIT 0-2 = Rate mantissa - */ - -#define MMCSD_CSD_TRANSPEED_TIMEVALUE(csd) ((csd[1] >> 3) & 0x0f) -#define MMCSD_CSD_TRANSPEED_TRANSFERRATEUNIT(csd) (csd[1] & 7) - -/* CCC 84-95 = Card command classes */ - -#define MMCSD_CSD_CCC(csd) ((csd[2] >> 4) & 0x0fff) - - /* READ_BL_LEN 80-83 = Max. read data block length */ - -#define MMCSD_CSD_READBLLEN(csd) (csd[2] & 0x0f) - -/* READ_BL_PARTIAL 79-79 = Partial blocks for read allowed */ - -#define MMCSD_CSD_READBLPARTIAL(csd) (csd[3] >> 15) - -/* WRITE_BLK_MISALIGN 78-78 = Write block misalignment */ - -#define MMCSD_CSD_WRITEBLKMISALIN(csd) ((csd[3] >> 14) & 1) - -/* READ_BLK_MISALIGN 77:77 = Read block misalignment */ - -#define MMCSD_CSD_READBLKMISALIN(csd) ((csd[3] >> 13) & 1) - -/* DSR_IMP 76-76 = DSR implemented */ - -#define MMCSD_CSD_DSRIMP(csd) ((csd[3] >> 12) & 1) - -/* C_SIZE 62-73 Device size */ - -#define MMCSD_CSD_CSIZE(csd) (((csd[3] & 0x03ff) << 2) | ((csd[4] >> 14) & 3)) - -/* VDD_R_CURR_MIN 59-61 = Max. read current at Vcc min */ - -#define MMCSD_CSD_VDDRCURRMIN(csd) ((csd[4] >> 11) & 7) - -/* VDD_R_CURR_MAX 56-58 = Max. read current at Vcc max */ - -#define MMCSD_CSD_VDDRCURRMAX(csd) ((csd[4] >> 8) & 7) - -/* VDD_W_CURR_MIN 53-55 = Max. write current at Vcc min */ - -#define MMCSD_CSD_VDDWCURRMIN(csd) ((csd[4] >> 5) & 7) - -/* VDD_W_CURR_MAX 50-52 = Max. write current at Vcc max */ - -#define MMCSD_CSD_VDDWCURRMAX(csd) ((csd[4] >> 2) & 7) - -/* C_SIZE_MULT 47-49 Device size multiplier */ - -#define MMCSD_CSD_CSIZEMULT(csd) (((csd[4] & 3) << 1) | (csd[5] >> 15)) - -/* ER_BLK_EN 46-46 =Erase single block enable (SD) */ - -#define SD_CSD_SDERBLKEN(csd) ((csd[5] >> 14) & 1) - -/* SECTOR_SIZE 39-45 = Erase sector size (SD) */ - -#define SD_CSD_SECTORSIZE(csd) ((csd[5] >> 7) & 0x7f) - -/* SECTOR_SIZE 42-46 = Erase sector size (MMC) */ - -#define MMC_CSD_SECTORSIZE(csd) ((csd[5] >> 10) & 0x1f) - -/* ER_GRP_SIZE 37-41 = Erase group size (MMC)*/ - -#define MMC_CSD_ERGRPSIZE(csd) ((csd[5] >> 5) & 0x1f) - -/* WP_GRP_SIZE 32-38 = Write protect group size (SD) */ - -#define SD_CSD_WPGRPSIZE(csd) (csd[5] & 0x7f) - -/* WP_GRP_SIZE 32-36 = Write protect group size (MMC) */ - -#define MMC_CSD_WPGRPSIZE(csd) (csd[5] & 0x1f) - -/* WP_GRP_EN 31-31 = Write protect group enable */ - -#define MMCSD_WPGRPEN(csd) (csd[6] >> 15) - -/* DFLT_ECC 29-30 = Manufacturer default ECC (MMC) */ - -#define MMC_CSD_DFLTECC(csd) ((csd[6] >> 13) & 3) - -/* R2W_FACTOR 26-28 = Write speed factor */ - -#define MMCSD_CSD_R2WFACTOR(csd) ((csd[6] >> 10) & 7) - -/* WRITE_BL_LEN 22-25 = Max. write data block length */ - -#define MMCSD_CSD_WRITEBLLEN(csd) ((csd[6] >> 6) & 0x0f) - -/* WRITE_BL_PARTIAL 21-21 = Partial blocks for write allowed */ - -#define MMCSD_CSD_WRITEBLPARTIAL(csd) ((csd[6] >> 5) & 1) - -/* Reserved 16-20 */ - -/* FILE_FORMAT_GROUP 15-15 = File format group */ - -#define MMCSD_CSD_FILEFORMATGRP(csd) (csd[7] >> 15) - -/* COPY 14-14 = Copy flag (OTP) */ - -#define MMCSD_CSD_COPY(csd) ((csd[7] >> 14) & 1) - -/* PERM_WRITE_PROTECT 13-13 = Permanent write protection */ - -#define MMCSD_CSD_PERMWRITEPROTECT(csd) ((csd[7] >> 13) & 1) - -/* TMP_WRITE_PROTECT 12-12 = Temporary write protection */ - -#define MMCSD_CSD_TMPWRITEPROTECT(csd) ((csd[7] >> 12) & 1) - -/* FILE_FORMAT 10-11 = File format */ - -#define MMCSD_CSD_FILEFORMAT(csd) ((csd[7] >> 10) & 3) - -/* ECC 8-9 = ECC (MMC) */ - -#define MMC_CSD_ECC(csd) ((csd[7] >> 8) & 3) - -/* CRC 1-7 = CRC */ - -#define MMCSD_CSD_CRC(csd) ((csd[7] >> 1) & 0x7f) - -/* Reserved 0-0 */ - -#else /* CONFIG_MMCSD_BE16 */ - -/* CSD_STRUCTURE 126-127 */ - -#define MMCSD_CSD_CSDSTRUCT(csd) (csd[0] >> 6) - -/* SPEC_VERS 122-125 = (word 0, bits 13:10) (MMC) Spec version */ - -#define MMC_CSD_SPECVERS(csd) ((csd[0] >> 2) & 0x0f) - -/* Reserved 120-155 */ - -/* TAAC 112-119 = Data read access-time-1 - * TIME_VALUE 3-6 = Time mantissa - * TIME_UNIT 0-2 = Time exponent - */ - -#define MMCSD_CSD_TAAC_TIMEVALUE(csd) ((csd[1] >> 3) & 0x0f) -#define MMCSD_CSD_TAAC_TIMEUNIT(csd) (csd[1] & 7) - -#define SD20_CSD_TAC_TIMEVALUE(csd) (1) -#define SD20_CSD_TAC_TIMEUNIT(csd) (6) - -/* NSAC 111:104 = Data read access-time-2 in CLK cycle(NSAC*100) */ - -#define MMCSD_CSD_NSAC(csd) (csd[2]) -#define SD20_CSD_NSAC(csd) (0) - -/* TRAN_SPEED 96-103 = Max. data transfer rate - * TIME_VALUE 3-6 = Rate exponent - * TRANSFER_RATE_UNIT 0-2 = Rate mantissa - */ - -#define MMCSD_CSD_TRANSPEED_TIMEVALUE(csd) ((csd[3] >> 3) & 0x0f) -#define MMCSD_CSD_TRANSPEED_TRANSFERRATEUNIT(csd) (csd[3] & 7) - -#define SD20_CSD_TRANSPEED_TIMEVALUE(csd) MMCSD_CSD_TRANSPEED_TIMEVALUE(csd) -#define SD20_CSD_TRANSPEED_TRANSFERRATEUNIT(csd) MMCSD_CSD_TRANSPEED_TRANSFERRATEUNIT(csd) - -/* CCC 84-95 = Card command classes */ - -#define MMCSD_CSD_CCC(csd) (((uint16_t)csd[4] << 4) | ((uint16_t)csd[5] >> 4)) -#define SD20_CSD_CCC(csd) MMCSD_CSD_CCC(csd) - - /* READ_BL_LEN 80-83 = Max. read data block length */ - -#define MMCSD_CSD_READBLLEN(csd) (csd[5] & 0x0f) -#define SD20_CSD_READBLLEN(csd) (9) - -/* READ_BL_PARTIAL 79-79 = Partial blocks for read allowed */ - -#define MMCSD_CSD_READBLPARTIAL(csd) (csd[6] >> 7) -#define SD20_CSD_READBLPARTIAL(csd) (0) - -/* WRITE_BLK_MISALIGN 78-78 = Write block misalignment */ - -#define MMCSD_CSD_WRITEBLKMISALIGN(csd) ((csd[6] >> 6) & 1) -#define SD20_CSD_WRITEBLKMISALIGN(csd) (0) - -/* READ_BLK_MISALIGN 77:77 = Read block misalignment */ - -#define MMCSD_CSD_READBLKMISALIGN(csd) ((csd[6] >> 5) & 1) -#define SD20_CSD_READBLKMISALIGN(csd) (0) - -/* DSR_IMP 76-76 = DSR implemented */ - -#define MMCSD_CSD_DSRIMP(csd) ((csd[6] >> 4) & 1) -#define SD20_CSD_DSRIMP(csd) MMCSD_CSD_DSRIMP(csd) - -/* C_SIZE 62-73 Device size */ - -#define MMCSD_CSD_CSIZE(csd) (((csd[6] & 3) << 10) | (csd[7] << 2) | (csd[8] >> 6)) -#define SD20_CSD_CSIZE(csd) ((((uint32_t)csd[7] & 0x3f) << 16) | (csd[8] << 8) | csd[9]) - -/* VDD_R_CURR_MIN 59-61 = Max. read current at Vcc min */ - -#define MMCSD_CSD_VDDRCURRMIN(csd) ((csd[8] >> 3) & 7) -#define SD20_CSD_VDDRCURRMIN(csd) (7) - -/* VDD_R_CURR_MAX 56-58 = Max. read current at Vcc max */ - -#define MMCSD_CSD_VDDRCURRMAX(csd) (csd[8] & 7) -#define SD20_CSD_VDDRCURRMAX(csd) (6) - -/* VDD_W_CURR_MIN 53-55 = Max. write current at Vcc min */ - -#define MMCSD_CSD_VDDWCURRMIN(csd) ((csd[9] >> 5) & 7) -#define SD20_CSD_VDDWCURRMIN(csd) (7) - -/* VDD_W_CURR_MAX 50-52 = Max. write current at Vcc max */ - -#define MMCSD_CSD_VDDWCURRMAX(csd) ((csd[9] >> 2) & 7) -#define SD20_CSD_VDDWCURRMAX(csd) (6) - -/* C_SIZE_MULT 47-49 Device size multiplier */ - -#define MMCSD_CSD_CSIZEMULT(csd) (((csd[9] & 3) << 1) | (csd[10] >> 7)) -#define SD20_CSD_CSIZEMULT(csd) (10-2) - -/* ER_BLK_EN 46-46 = Erase single block enable (SD) */ - -#define SD_CSD_SDERBLKEN(csd) ((csd[10] >> 6) & 1) -#define SD20_CSD_SDERBLKEN(csd) (1) - -/* SECTOR_SIZE 39-45 = Erase sector size (SD) */ - -#define SD_CSD_SECTORSIZE(csd) (((csd[10] & 0x3f) << 1) | (csd[11] >> 7)) -#define SD20_CSD_SECTORSIZE(csd) (0x7f) - -/* SECTOR_SIZE 42-46 = Erase sector size (MMC) */ - -#define MMC_CSD_SECTORSIZE(csd) ((csd[10] >> 2) & 0x1f) - -/* ER_GRP_SIZE 37-41 = Erase group size (MMC)*/ - -#define MMC_CSD_ERGRPSIZE(csd) (((csd[10] & 3) << 3) | (csd[11] > 5)) - -/* WP_GRP_SIZE 32-38 = Write protect group size (SD) */ - -#define SD_CSD_WPGRPSIZE(csd) (csd[11] & 0x7f) -#define SD20_CSD_WPGRPSIZE(csd) (0) - -/* WP_GRP_SIZE 32-36 = Write protect group size (MMC) */ - -#define MMC_CSD_WPGRPSIZE(csd) (csd[11] & 0x1f) - -/* WP_GRP_EN 31-31 = Write protect group enable */ - -#define MMCSD_WPGRPEN(csd) (csd[12] >> 7) -#define SD20_WPGRPEN(csd) (0) - -/* DFLT_ECC 29-30 = Manufacturer default ECC (MMC) */ - -#define MMC_CSD_DFLTECC(csd) ((csd[12] >> 5) & 3) - -/* R2W_FACTOR 26-28 = Write speed factor */ - -#define MMCSD_CSD_R2WFACTOR(csd) ((csd[12] >> 2) & 7) -#define SD20_CSD_R2WFACTOR(csd) (2) - -/* WRITE_BL_LEN 22-25 = Max. write data block length */ - -#define MMCSD_CSD_WRITEBLLEN(csd) (((csd[12] & 3) << 2) | (csd[13] >> 6)) -#define SD20_CSD_WRITEBLLEN(csd) (9) - -/* WRITE_BL_PARTIAL 21-21 = Partial blocks for write allowed */ - -#define MMCSD_CSD_WRITEBLPARTIAL(csd) ((csd[13] >> 5) & 1) -#define SD20_CSD_WRITEBLPARTIAL(csd) (0) - -/* Reserved 16-20 */ - -/* FILE_FORMAT_GROUP 15-15 = File format group */ - -#define MMCSD_CSD_FILEFORMATGRP(csd) (csd[14] >> 7) -#define SD20_CSD_FILEFORMATGRP(csd) (0) - -/* COPY 14-14 = Copy flag (OTP) */ - -#define MMCSD_CSD_COPY(csd) ((csd[14] >> 6) & 1) -#define SD20_CSD_COPY(csd) MMCSD_CSD_COPY(csd) - -/* PERM_WRITE_PROTECT 13-13 = Permanent write protection */ - -#define MMCSD_CSD_PERMWRITEPROTECT(csd) ((csd[14] >> 5) & 1) -#define SD20_CSD_PERMWRITEPROTECT(csd) MMCSD_CSD_PERMWRITEPROTECT(csd) - -/* TMP_WRITE_PROTECT 12-12 = Temporary write protection */ - -#define MMCSD_CSD_TMPWRITEPROTECT(csd) ((csd[14] >> 4) & 1) -#define SD20_CSD_TMPWRITEPROTECT(csd) MMCSD_CSD_TMPWRITEPROTECT(csd) - -/* FILE_FORMAT 10-11 = File format */ - -#define MMCSD_CSD_FILEFORMAT(csd) ((csd[14] >> 2) & 3) -#define SD20_CSD_FILEFORMAT(csd) (0) - -/* ECC 8-9 = ECC (MMC) */ - -#define MMC_CSD_ECC(csd) (csd[14] & 3) - -/* CRC 1-7 = CRC */ - -#define MMCSD_CSD_CRC(csd) (csd[15] >> 1) -#define SD20_CSD_CRC(csd) MMCSD_CSD_CRC(csd) - -/* Reserved 0-0 */ - -#endif /* CONFIG_MMCSD_BE16 */ - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#if defined(__cplusplus) -} -#endif -#endif /* __DRIVERS_MMCSD_MMCSD_CSD_H */ diff --git a/nuttx/drivers/mmcsd/mmcsd_debug.c b/nuttx/drivers/mmcsd/mmcsd_debug.c deleted file mode 100644 index 8cb5b2a2a..000000000 --- a/nuttx/drivers/mmcsd/mmcsd_debug.c +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************************** - * drivers/mmcsd/mmcsd_debug.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include "mmcsd_csd.h" -#include "mmcsd_internal.h" - -/**************************************************************************** - * Pre-Processor Definitions - ****************************************************************************/ - -/* This needs to match the logic in include/debug.h */ - -#ifdef CONFIG_CPP_HAVE_VARARGS -# define message(format, arg...) syslog(format, ##arg) -#else -# define message syslog -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_dmpcsd - * - * Description: - * Dump the contents of the CSD - * - ****************************************************************************/ - -#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -void mmcsd_dmpcsd(FAR const uint8_t *csd, uint8_t cardtype) -{ - bool mmc = (cardtype == MMCSD_CARDTYPE_MMC); - bool sd2 = (MMCSD_CSD_CSDSTRUCT(csd) == 1); - - fvdbg("CSD\n"); - fvdbg(" CSD_STRUCTURE: 1.%d\n", MMCSD_CSD_CSDSTRUCT(csd)); - if (mmc) - { - fvdbg(" MMC SPEC_VERS: %d\n", MMC_CSD_SPECVERS(csd)); - } - fvdbg(" TAAC:\n", - sd2 ? SD20_CSD_TAC_TIMEVALUE(csd) : MMCSD_CSD_TAAC_TIMEVALUE(csd)); - fvdbg(" TIME_VALUE: 0x%02x\n", - sd2 ? SD20_CSD_TAC_TIMEVALUE(csd) : MMCSD_CSD_TAAC_TIMEVALUE(csd)); - fvdbg(" TIME_UNIT: 0x%02x\n", - sd2 ? SD20_CSD_TAC_TIMEUNIT(csd) : MMCSD_CSD_TAAC_TIMEUNIT(csd)); - fvdbg(" NSAC: 0x%02x\n", - sd2 ? SD20_CSD_NSAC(csd) : MMCSD_CSD_NSAC(csd)); - fvdbg(" TRAN_SPEED:\n"); - fvdbg(" TIME_VALUE: 0x%02x\n", - sd2 ? SD20_CSD_TRANSPEED_TIMEVALUE(csd) : MMCSD_CSD_TRANSPEED_TIMEVALUE(csd)); - fvdbg(" RATE_UNIT: 0x%02x\n", - sd2 ? SD20_CSD_TRANSPEED_TRANSFERRATEUNIT(csd) : MMCSD_CSD_TRANSPEED_TRANSFERRATEUNIT(csd)); - fvdbg(" CCC: 0x%03x\n", - sd2 ? SD20_CSD_CCC(csd) : MMCSD_CSD_CCC(csd)); - fvdbg(" READ_BL_LEN: %d\n", - sd2 ? SD20_CSD_READBLLEN(csd) : MMCSD_CSD_READBLLEN(csd)); - fvdbg(" READ_BL_PARTIAL: %d\n", - sd2 ? SD20_CSD_READBLPARTIAL(csd) : MMCSD_CSD_READBLPARTIAL(csd)); - fvdbg(" WRITE_BLK_MISALIGN: %d\n", - sd2 ? SD20_CSD_WRITEBLKMISALIGN(csd) : MMCSD_CSD_WRITEBLKMISALIGN(csd)); - fvdbg(" READ_BLK_MISALIGN: %d\n", - sd2 ? SD20_CSD_READBLKMISALIGN(csd) : MMCSD_CSD_READBLKMISALIGN(csd)); - fvdbg(" DSR_IMP: %d\n", - sd2 ? SD20_CSD_DSRIMP(csd) : MMCSD_CSD_DSRIMP(csd)); - fvdbg(" C_SIZE: %d\n", - sd2 ? SD20_CSD_CSIZE(csd) : MMCSD_CSD_CSIZE(csd)); - fvdbg(" VDD_R_CURR_MIN: %d\n", - sd2 ? SD20_CSD_VDDRCURRMIN(csd) : MMCSD_CSD_VDDRCURRMIN(csd)); - fvdbg(" VDD_R_CURR_MAX: %d\n", - sd2 ? SD20_CSD_VDDRCURRMAX(csd) : MMCSD_CSD_VDDRCURRMAX(csd)); - fvdbg(" VDD_W_CURR_MIN: %d\n", - sd2 ? SD20_CSD_VDDWCURRMIN(csd) : MMCSD_CSD_VDDWCURRMIN(csd)); - fvdbg(" VDD_W_CURR_MAX: %d\n", - sd2 ? SD20_CSD_VDDWCURRMAX(csd) : MMCSD_CSD_VDDWCURRMAX(csd)); - fvdbg(" C_SIZE_MULT: %d\n", - sd2 ? SD20_CSD_CSIZEMULT(csd) : MMCSD_CSD_CSIZEMULT(csd)); - if (mmc) - { - fvdbg(" MMC SECTOR_SIZE: %d\n", MMC_CSD_SECTORSIZE(csd)); - fvdbg(" MMC ER_GRP_SIZE: %d\n", MMC_CSD_ERGRPSIZE(csd)); - fvdbg(" MMC WP_GRP_SIZE: %d\n", MMC_CSD_WPGRPSIZE(csd)); - fvdbg(" MMC DFLT_ECC: %d\n", MMC_CSD_DFLTECC(csd)); - } - else - { - fvdbg(" SD ER_BLK_EN: %d\n", - sd2 ? SD20_CSD_SDERBLKEN(csd) : SD_CSD_SDERBLKEN(csd)); - fvdbg(" SD SECTOR_SIZE: %d\n", - sd2 ? SD20_CSD_SECTORSIZE(csd) : SD_CSD_SECTORSIZE(csd)); - fvdbg(" SD WP_GRP_SIZE: %d\n", - sd2 ? SD_CSD_WPGRPSIZE(csd) : SD_CSD_WPGRPSIZE(csd)); - } - fvdbg(" WP_GRP_EN: %d\n", - sd2 ? SD20_WPGRPEN(csd) : MMCSD_WPGRPEN(csd)); - fvdbg(" R2W_FACTOR: %d\n", - sd2 ? SD20_CSD_R2WFACTOR(csd) : MMCSD_CSD_R2WFACTOR(csd)); - fvdbg(" WRITE_BL_LEN: %d\n", - sd2 ? SD20_CSD_WRITEBLLEN(csd) : MMCSD_CSD_WRITEBLLEN(csd)); - fvdbg(" WRITE_BL_PARTIAL: %d\n", - sd2 ? SD20_CSD_WRITEBLPARTIAL(csd) : MMCSD_CSD_WRITEBLPARTIAL(csd)); - fvdbg(" FILE_FORMAT_GROUP: %d\n", - sd2 ? SD20_CSD_FILEFORMATGRP(csd) : MMCSD_CSD_FILEFORMATGRP(csd)); - fvdbg(" COPY: %d\n", - sd2 ? SD20_CSD_COPY(csd) : MMCSD_CSD_COPY(csd)); - fvdbg(" PERM_WRITE_PROTECT: %d\n", - sd2 ? SD20_CSD_PERMWRITEPROTECT(csd) : MMCSD_CSD_PERMWRITEPROTECT(csd)); - fvdbg(" TMP_WRITE_PROTECT: %d\n", - sd2 ?SD20_CSD_TMPWRITEPROTECT(csd) : MMCSD_CSD_TMPWRITEPROTECT(csd)); - fvdbg(" FILE_FORMAT: %d\n", - sd2 ? SD20_CSD_FILEFORMAT(csd) : MMCSD_CSD_FILEFORMAT(csd)); - if (mmc) - { - fvdbg(" MMC ECC: %d\n", - sd2 ? MMC_CSD_ECC(csd) : MMC_CSD_ECC(csd)); - } - fvdbg(" CRC: %02x\n", - sd2 ? SD20_CSD_CRC(csd) : MMCSD_CSD_CRC(csd)); -} -#endif diff --git a/nuttx/drivers/mmcsd/mmcsd_internal.h b/nuttx/drivers/mmcsd/mmcsd_internal.h deleted file mode 100644 index ed669cdfa..000000000 --- a/nuttx/drivers/mmcsd/mmcsd_internal.h +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** - * drivers/mmcsd/mmcsd_internal.h - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_MMCSD_MMCSD_INTERNAL_H -#define __DRIVERS_MMCSD_MMCSD_INTERNAL_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include - -/**************************************************************************** - * Pre-Processor Definitions - ****************************************************************************/ - -/* Enable excessive debug options */ - -#undef CONFIG_MMCSD_DUMPALL /* MUST BE DEFINED MANUALLY */ - -#if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_FS) -# undef CONFIG_MMCSD_DUMPALL -#endif - -/* Card type */ - -#define MMCSD_CARDTYPE_UNKNOWN 0 /* Unknown card type */ -#define MMCSD_CARDTYPE_MMC 1 /* Bit 0: MMC card */ -#define MMCSD_CARDTYPE_SDV1 2 /* Bit 1: SD version 1.x */ -#define MMCSD_CARDTYPE_SDV2 4 /* Bit 2: SD version 2.x with byte addressing */ -#define MMCSD_CARDTYPE_BLOCK 8 /* Bit 3: SD version 2.x with block addressing */ - -#define IS_MMC(t) (((t) & MMCSD_CARDTYPE_MMC) != 0) -#define IS_SD(t) (((t) & (MMCSD_CARDTYPE_SDV1|MMCSD_CARDTYPE_SDV2)) != 0) -#define IS_SDV1(t) (((t) & MMCSD_CARDTYPE_SDV1) != 0) -#define IS_SDV2(t) (((t) & MMCSD_CARDTYPE_SDV2) != 0) -#define IS_BLOCK(t) (((t) & MMCSD_CARDTYPE_BLOCK) != 0) - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#ifdef CONFIG_MMCSD_DUMPALL -# define mmcsd_dumpbuffer(m,b,l) fvdbgdumpbuffer(m,b,l) -#else -# define mmcsd_dumpbuffer(m,b,l) -#endif - -#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -EXTERN void mmcsd_dmpcsd(FAR const uint8_t *csd, uint8_t cardtype); -#else -# define mmcsd_dmpcsd(csd,cadtype) -#endif - -#undef EXTERN -#if defined(__cplusplus) -} -#endif -#endif /* __DRIVERS_MMCSD_MMCSD_INTERNAL_H */ diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c deleted file mode 100644 index 3caa61583..000000000 --- a/nuttx/drivers/mmcsd/mmcsd_sdio.c +++ /dev/null @@ -1,3186 +0,0 @@ -/**************************************************************************** - * drivers/mmcsd/mmcsd_sdio.c - * - * Copyright (C) 2009-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#if defined (CONFIG_MMCSD) && defined (CONFIG_MMCSD_SDIO) - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mmcsd_internal.h" -#include "mmcsd_sdio.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* The maximum number of references on the driver (because a uint8_t is used. - * Use a larger type if more references are needed. - */ - -#define MAX_CREFS 0xff - -/* Timing (all in units of microseconds) */ - -#define MMCSD_POWERUP_DELAY ((useconds_t)250) /* 74 clock cycles @ 400KHz = 185uS */ -#define MMCSD_IDLE_DELAY ((useconds_t)50000) /* Short delay to allow change to IDLE state */ -#define MMCSD_DSR_DELAY ((useconds_t)100000) /* Time to wait after setting DSR */ -#define MMCSD_CLK_DELAY ((useconds_t)500000) /* Delay after changing clock speeds */ - -/* Data delays (all in units of milliseconds). - * - * For MMC & SD V1.x, these should be based on Nac = TAAC + NSAC; The maximum - * value of TAAC is 80MS and the maximum value of NSAC is 25.5K clock cycle. - * For SD V2.x, a fixed delay of 100MS is recommend which is pretty close to - * the worst case SD V1.x Nac. Here we just use 100MS delay for all data - * transfers. - */ - -#define MMCSD_SCR_DATADELAY (100) /* Wait up to 100MS to get SCR */ -#define MMCSD_BLOCK_DATADELAY (100) /* Wait up to 100MS to get one data block */ - -#define IS_EMPTY(priv) (priv->type == MMCSD_CARDTYPE_UNKNOWN) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure is contains the unique state of the MMC/SD block driver */ - -struct mmcsd_state_s -{ - FAR struct sdio_dev_s *dev; /* The SDIO device bound to this instance */ - uint8_t crefs; /* Open references on the driver */ - sem_t sem; /* Assures mutually exclusive access to the slot */ - - /* Status flags */ - - uint8_t probed:1; /* true: mmcsd_probe() discovered a card */ - uint8_t widebus:1; /* true: Wide 4-bit bus selected */ - uint8_t mediachanged:1; /* true: Media changed since last check */ - uint8_t wrbusy:1; /* true: Last transfer was a write, card may be busy */ - uint8_t wrprotect:1; /* true: Card is write protected (from CSD) */ - uint8_t locked:1; /* true: Media is locked (from R1) */ - uint8_t dsrimp:1; /* true: card supports CMD4/DSR setting (from CSD) */ -#ifdef CONFIG_SDIO_DMA - uint8_t dma:1; /* true: hardware supports DMA */ -#endif - - uint8_t mode:2; /* (See MMCSDMODE_* definitions) */ - uint8_t type:4; /* Card type (See MMCSD_CARDTYPE_* definitions) */ - uint8_t buswidth:4; /* Bus widthes supported (SD only) */ - uint16_t selblocklen; /* The currently selected block length */ - uint16_t rca; /* Relative Card Address (RCS) register */ - - /* Memory card geometry (extracted from the CSD) */ - - uint8_t blockshift; /* Log2 of blocksize */ - uint16_t blocksize; /* Read block length (== block size) */ - uint32_t nblocks; /* Number of blocks */ - -#ifdef CONFIG_HAVE_LONG_LONG - uint64_t capacity; /* Total capacity of volume */ -#else - uint32_t capacity; /* Total capacity of volume (Limited to 4Gb) */ -#endif - /* Read-ahead and write buffering support */ - -#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) - struct rwbuffer_s rwbuffer; -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Misc Helpers *************************************************************/ - -static void mmcsd_takesem(FAR struct mmcsd_state_s *priv); - -#ifndef CONFIG_SDIO_MUXBUS -# define mmcsd_givesem(p) sem_post(&priv->sem); -#endif - -/* Command/response helpers *************************************************/ - -static int mmcsd_sendcmdpoll(FAR struct mmcsd_state_s *priv, - uint32_t cmd, uint32_t arg); -static int mmcsd_recvR1(FAR struct mmcsd_state_s *priv, uint32_t cmd); -static int mmcsd_recvR6(FAR struct mmcsd_state_s *priv, uint32_t cmd); -static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32_t scr[2]); - -static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, - uint32_t csd[4]); -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -static void mmcsd_decodeCID(FAR struct mmcsd_state_s *priv, - uint32_t cid[4]); -#else -# define mmcsd_decodeCID(priv,cid) -#endif -static void mmcsd_decodeSCR(FAR struct mmcsd_state_s *priv, - uint32_t scr[2]); - -static int mmcsd_getR1(FAR struct mmcsd_state_s *priv, FAR uint32_t *r1); -static int mmcsd_verifystate(FAR struct mmcsd_state_s *priv, - uint32_t status); - -/* Transfer helpers *********************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv); -#endif -static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv, - sdio_eventset_t failevents, uint32_t timeout); -static int mmcsd_transferready(FAR struct mmcsd_state_s *priv); -#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE -static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv); -#endif -static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv, - uint32_t blocklen); -static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, - FAR uint8_t *buffer, off_t startblock); -#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE -static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, - FAR uint8_t *buffer, off_t startblock, size_t nblocks); -#endif -#ifdef CONFIG_FS_READAHEAD -static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, - off_t startblock, size_t nblocks); -#endif -#ifdef CONFIG_FS_WRITABLE -static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, - FAR const uint8_t *buffer, off_t startblock); -#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE -static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, - FAR const uint8_t *buffer, off_t startblock, size_t nblocks); -#endif -#ifdef CONFIG_FS_WRITEBUFFER -static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, - off_t startblock, size_t nblocks); -#endif -#endif - -/* Block driver methods *****************************************************/ - -static int mmcsd_open(FAR struct inode *inode); -static int mmcsd_close(FAR struct inode *inode); -static ssize_t mmcsd_read(FAR struct inode *inode, FAR unsigned char *buffer, - size_t startsector, unsigned int nsectors); -#ifdef CONFIG_FS_WRITABLE -static ssize_t mmcsd_write(FAR struct inode *inode, - FAR const unsigned char *buffer, size_t startsector, - unsigned int nsectors); -#endif -static int mmcsd_geometry(FAR struct inode *inode, - FAR struct geometry *geometry); -static int mmcsd_ioctl(FAR struct inode *inode, int cmd, - unsigned long arg); - -/* Initialization/uninitialization/reset ************************************/ - -static void mmcsd_mediachange(FAR void *arg); -static int mmcsd_widebus(FAR struct mmcsd_state_s *priv); -#ifdef CONFIG_MMCSD_MMCSUPPORT -static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv); -#endif -static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv); -static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv); -static int mmcsd_probe(FAR struct mmcsd_state_s *priv); -static int mmcsd_removed(FAR struct mmcsd_state_s *priv); -static int mmcsd_hwinitialize(FAR struct mmcsd_state_s *priv); -static void mmcsd_hwuninitialize(FAR struct mmcsd_state_s *priv); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct block_operations g_bops = -{ - mmcsd_open, /* open */ - mmcsd_close, /* close */ - mmcsd_read, /* read */ -#ifdef CONFIG_FS_WRITABLE - mmcsd_write, /* write */ -#else - NULL, /* write */ -#endif - mmcsd_geometry, /* geometry */ - mmcsd_ioctl /* ioctl */ -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Misc Helpers - ****************************************************************************/ - -static void mmcsd_takesem(FAR struct mmcsd_state_s *priv) -{ - /* Take the semaphore, giving exclusive access to the driver (perhaps - * waiting) - */ - - while (sem_wait(&priv->sem) != 0) - { - /* The only case that an error should occur here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } - - /* Lock the bus if mutually exclusive access to the SDIO bus is required - * on this platform. - */ - -#ifdef CONFIG_SDIO_MUXBUS - SDIO_LOCK(priv->dev, TRUE); -#endif -} - -#ifdef CONFIG_SDIO_MUXBUS -static void mmcsd_givesem(FAR struct mmcsd_state_s *priv) -{ - /* Release the SDIO bus lock, then the MMC/SD driver semaphore in the - * opposite order that they were taken to assure that no deadlock - * conditions will arise. - */ - - SDIO_LOCK(priv->dev, FALSE); - sem_post(&priv->sem); -} -#endif - -/**************************************************************************** - * Command/Response Helpers - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_sendcmdpoll - * - * Description: - * Send a command and poll-wait for the response. - * - ****************************************************************************/ - -static int mmcsd_sendcmdpoll(FAR struct mmcsd_state_s *priv, uint32_t cmd, - uint32_t arg) -{ - int ret; - - /* Send the command */ - - ret = SDIO_SENDCMD(priv->dev, cmd, arg); - if (ret == OK) - { - /* Then poll-wait until the response is available */ - - ret = SDIO_WAITRESPONSE(priv->dev, cmd); - if (ret != OK) - { - fdbg("ERROR: Wait for response to cmd: %08x failed: %d\n", cmd, ret); - } - } - return ret; -} - -/**************************************************************************** - * Name: mmcsd_sendcmd4 - * - * Description: - * Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been - * provided and (2) the card supports a DSR register. If no DSR value - * the card default value (0x0404) will be used. - * - ****************************************************************************/ - -static inline int mmcsd_sendcmd4(FAR struct mmcsd_state_s *priv) -{ - int ret = OK; - -#ifdef CONFIG_MMCSD_DSR - /* The dsr_imp bit from the CSD will tell us if the card supports setting - * the DSR via CMD4 or not. - */ - - if (priv->dsrimp != false) - { - /* CMD4 = SET_DSR will set the cards DSR register. The DSR and CMD4 - * support are optional. However, since this is a broadcast command - * with no response (like CMD0), we will never know if the DSR was - * set correctly or not - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD4, CONFIG_MMCSD_DSR << 16); - up_udelay(MMCSD_DSR_DELAY); - - /* Send it again to have more confidence */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD4, CONFIG_MMCSD_DSR << 16); - up_udelay(MMCSD_DSR_DELAY); - } -#endif - return ret; -} - -/**************************************************************************** - * Name: mmcsd_recvR1 - * - * Description: - * Receive R1 response and check for errors. - * - ****************************************************************************/ - -static int mmcsd_recvR1(FAR struct mmcsd_state_s *priv, uint32_t cmd) -{ - uint32_t r1; - int ret; - - /* Get the R1 response from the hardware */ - - ret = SDIO_RECVR1(priv->dev, cmd, &r1); - if (ret == OK) - { - /* Check if R1 reports an error */ - - if ((r1 & MMCSD_R1_ERRORMASK) != 0) - { - /* Card locked is considered an error. Save the card locked - * indication for later use. - */ - - fvdbg("ERROR: R1=%08x\n", r1); - priv->locked = ((r1 & MMCSD_R1_CARDISLOCKED) != 0); - ret = -EIO; - } - } - return ret; -} - -/**************************************************************************** - * Name: mmcsd_recvR6 - * - * Description: - * Receive R6 response and check for errors. On success, priv->rca is set - * to the received RCA - * - ****************************************************************************/ - -static int mmcsd_recvR6(FAR struct mmcsd_state_s *priv, uint32_t cmd) -{ - uint32_t r6 = 0; - int ret; - - /* R6 Published RCA Response (48-bit, SD card only) - * 47 0 Start bit - * 46 0 Transmission bit (0=from card) - * 45:40 bit5 - bit0 Command index (0-63) - * 39:8 bit31 - bit0 32-bit Argument Field, consisting of: - * [31:16] New published RCA of card - * [15:0] Card status bits {23,22,19,12:0} - * 7:1 bit6 - bit0 CRC7 - * 0 1 End bit - * - * Get the R1 response from the hardware - */ - - ret = SDIO_RECVR6(priv->dev, cmd, &r6); - if (ret == OK) - { - /* Check if R6 reports an error */ - - if ((r6 & MMCSD_R6_ERRORMASK) == 0) - { - /* No, save the RCA and return success */ - - priv->rca = (uint16_t)(r6 >> 16); - return OK; - } - - /* Otherwise, return an I/O failure */ - - ret = -EIO; - } - - fdbg("ERROR: Failed to get RCA. R6=%08x: %d\n", r6, ret); - return ret; -} - -/**************************************************************************** - * Name: mmcsd_getSCR - * - * Description: - * Obtain the SD card's Configuration Register (SCR) - * - * Returned Value: - * OK on success; a negated ernno on failure. - * - ****************************************************************************/ - -static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32_t scr[2]) -{ - int ret; - - /* Set Block Size To 8 Bytes */ - - ret = mmcsd_setblocklen(priv, 8); - if (ret != OK) - { - fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret); - return ret; - } - - /* Send CMD55 APP_CMD with argument as card's RCA */ - - mmcsd_sendcmdpoll(priv, SD_CMD55, (uint32_t)priv->rca << 16); - ret = mmcsd_recvR1(priv, SD_CMD55); - if (ret != OK) - { - fdbg("ERROR: RECVR1 for CMD55 failed: %d\n", ret); - return ret; - } - - /* Setup up to receive data with interrupt mode */ - - SDIO_BLOCKSETUP(priv->dev, 8, 1); - SDIO_RECVSETUP(priv->dev, (FAR uint8_t*)scr, 8); - - /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */ - - (void)SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR); - mmcsd_sendcmdpoll(priv, SD_ACMD51, 0); - ret = mmcsd_recvR1(priv, SD_ACMD51); - if (ret != OK) - { - fdbg("ERROR: RECVR1 for ACMD51 failed: %d\n", ret); - SDIO_CANCEL(priv->dev); - return ret; - } - - /* Wait for data to be transferred */ - - ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, MMCSD_SCR_DATADELAY); - if (ret != OK) - { - fdbg("ERROR: mmcsd_eventwait for READ DATA failed: %d\n", ret); - } - return ret; -} - -/**************************************************************************** - * Name: mmcsd_decodeCSD - * - * Description: - * Decode and extract necessary information from the CSD. If debug is - * enabled, then decode and show the full contents of the CSD. - * - * Returned Value: - * OK on success; a negated ernno on failure. On success, the following - * values will be set in the driver state structure: - * - * priv->dsrimp true: card supports CMD4/DSR setting (from CSD) - * priv->wrprotect true: card is write protected (from CSD) - * priv->blocksize Read block length (== block size) - * priv->nblocks Number of blocks - * priv->capacity Total capacity of volume - * - ****************************************************************************/ - -static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4]) -{ -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) - struct mmcsd_csd_s decoded; -#endif - unsigned int readbllen; - bool permwriteprotect; - bool tmpwriteprotect; - - /* Word 1: Bits 127-96: - * - * CSD_STRUCTURE 127:126 CSD structure - * SPEC_VERS 125:122 (MMC) Spec version - * TAAC 119:112 Data read access-time-1 - * TIME_VALUE 6:3 Time mantissa - * TIME_UNIT 2:0 Time exponent - * NSAC 111:104 Data read access-time-2 in CLK cycle(NSAC*100) - * TRAN_SPEED 103:96 Max. data transfer rate - * TIME_VALUE 6:3 Rate exponent - * TRANSFER_RATE_UNIT 2:0 Rate mantissa - */ - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) - memset(&decoded, 0, sizeof(struct mmcsd_csd_s)); - decoded.csdstructure = csd[0] >> 30; - decoded.mmcspecvers = (csd[0] >> 26) & 0x0f; - decoded.taac.timevalue = (csd[0] >> 19) & 0x0f; - decoded.taac.timeunit = (csd[0] >> 16) & 7; - decoded.nsac = (csd[0] >> 8) & 0xff; - decoded.transpeed.timevalue = (csd[0] >> 3) & 0x0f; - decoded.transpeed.transferrateunit = csd[0] & 7; -#endif - - /* Word 2: Bits 64:95 - * CCC 95:84 Card command classes - * READ_BL_LEN 83:80 Max. read data block length - * READ_BL_PARTIAL 79:79 Partial blocks for read allowed - * WRITE_BLK_MISALIGN 78:78 Write block misalignment - * READ_BLK_MISALIGN 77:77 Read block misalignment - * DSR_IMP 76:76 DSR implemented - * Byte addressed SD and MMC: - * C_SIZE 73:62 Device size - * Block addressed SD: - * 75:70 (reserved) - * C_SIZE 48:69 Device size - */ - - priv->dsrimp = (csd[1] >> 12) & 1; - readbllen = (csd[1] >> 16) & 0x0f; - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) - decoded.ccc = (csd[1] >> 20) & 0x0fff; - decoded.readbllen = (csd[1] >> 16) & 0x0f; - decoded.readblpartial = (csd[1] >> 15) & 1; - decoded.writeblkmisalign = (csd[1] >> 14) & 1; - decoded.readblkmisalign = (csd[1] >> 13) & 1; - decoded.dsrimp = priv->dsrimp; -#endif - - /* Word 3: Bits 32-63 - * - * Byte addressed SD: - * C_SIZE 73:62 Device size - * VDD_R_CURR_MIN 61:59 Max. read current at Vcc min - * VDD_R_CURR_MAX 58:56 Max. read current at Vcc max - * VDD_W_CURR_MIN 55:53 Max. write current at Vcc min - * VDD_W_CURR_MAX 52:50 Max. write current at Vcc max - * C_SIZE_MULT 49:47 Device size multiplier - * SD_ER_BLK_EN 46:46 Erase single block enable (SD only) - * SD_SECTOR_SIZE 45:39 Erase sector size - * SD_WP_GRP_SIZE 38:32 Write protect group size - * Block addressed SD: - * 75:70 (reserved) - * C_SIZE 48:69 Device size - * 47:47 (reserved) - * SD_ER_BLK_EN 46:46 Erase single block enable (SD only) - * SD_SECTOR_SIZE 45:39 Erase sector size - * SD_WP_GRP_SIZE 38:32 Write protect group size - * MMC: - * C_SIZE 73:62 Device size - * VDD_R_CURR_MIN 61:59 Max. read current at Vcc min - * VDD_R_CURR_MAX 58:56 Max. read current at Vcc max - * VDD_W_CURR_MIN 55:53 Max. write current at Vcc min - * VDD_W_CURR_MAX 52:50 Max. write current at Vcc max - * C_SIZE_MULT 49:47 Device size multiplier - * MMC_SECTOR_SIZE 46:42 Erase sector size - * MMC_ER_GRP_SIZE 41:37 Erase group size (MMC) - * MMC_WP_GRP_SIZE 36:32 Write protect group size - */ - - if (IS_BLOCK(priv->type)) - { - /* Block addressed SD: - * - * C_SIZE: 69:64 from Word 2 and 63:48 from Word 3 - * - * 512 = (1 << 9) - * 1024 = (1 << 10) - * 512*1024 = (1 << 19) - */ - - uint32_t csize = ((csd[1] & 0x3f) << 16) | (csd[2] >> 16); -#ifdef CONFIG_HAVE_LONG_LONG - priv->capacity = ((uint64_t)(csize + 1)) << 19; -#else - priv->capacity = (csize + 1) << 19; -#endif - priv->blockshift = 9; - priv->blocksize = 1 << 9; - priv->nblocks = priv->capacity >> 9; - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) - decoded.u.sdblock.csize = csize; - decoded.u.sdblock.sderblen = (csd[2] >> 14) & 1; - decoded.u.sdblock.sdsectorsize = (csd[2] >> 7) & 0x7f; - decoded.u.sdblock.sdwpgrpsize = csd[2] & 0x7f; -#endif - } - else - { - /* Byte addressed SD: - * - * C_SIZE: 73:64 from Word 2 and 63:62 from Word 3 - */ - - uint16_t csize = ((csd[1] & 0x03ff) << 2) | ((csd[2] >> 30) & 3); - uint8_t csizemult = (csd[2] >> 15) & 7; - - priv->nblocks = ((uint32_t)csize + 1) * (1 << (csizemult + 2)); - priv->blockshift = readbllen; - priv->blocksize = (1 << readbllen); - priv->capacity = (priv->nblocks << readbllen); - - /* Some devices, such as 2Gb devices, report blocksizes larger than 512 bytes - * but still expect to be accessed with a 512 byte blocksize. - * - * NOTE: A minor optimization would be to eliminated priv->blocksize and - * priv->blockshift: Those values will be 512 and 9 in all cases anyway. - */ - - if (priv->blocksize > 512) - { - priv->nblocks <<= (priv->blockshift - 9); - priv->blocksize = 512; - priv->blockshift = 9; - } - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) - if (IS_SD(priv->type)) - { - decoded.u.sdbyte.csize = csize; - decoded.u.sdbyte.vddrcurrmin = (csd[2] >> 27) & 7; - decoded.u.sdbyte.vddrcurrmax = (csd[2] >> 24) & 7; - decoded.u.sdbyte.vddwcurrmin = (csd[2] >> 21) & 7; - decoded.u.sdbyte.vddwcurrmax = (csd[2] >> 18) & 7; - decoded.u.sdbyte.csizemult = csizemult; - decoded.u.sdbyte.sderblen = (csd[2] >> 14) & 1; - decoded.u.sdbyte.sdsectorsize = (csd[2] >> 7) & 0x7f; - decoded.u.sdbyte.sdwpgrpsize = csd[2] & 0x7f; - } -#ifdef CONFIG_MMCSD_MMCSUPPORT - else if (IS_MMC(priv->type)) - { - decoded.u.mmc.csize = csize; - decoded.u.mmc.vddrcurrmin = (csd[2] >> 27) & 7; - decoded.u.mmc.vddrcurrmax = (csd[2] >> 24) & 7; - decoded.u.mmc.vddwcurrmin = (csd[2] >> 21) & 7; - decoded.u.mmc.vddwcurrmax = (csd[2] >> 18) & 7; - decoded.u.mmc.csizemult = csizemult; - decoded.u.mmc.er.mmc22.sectorsize = (csd[2] >> 10) & 0x1f; - decoded.u.mmc.er.mmc22.ergrpsize = (csd[2] >> 5) & 0x1f; - decoded.u.mmc.mmcwpgrpsize = csd[2] & 0x1f; - } -#endif -#endif - } - - /* Word 4: Bits 0-31 - * WP_GRP_EN 31:31 Write protect group enable - * MMC DFLT_ECC 30:29 Manufacturer default ECC (MMC only) - * R2W_FACTOR 28:26 Write speed factor - * WRITE_BL_LEN 25:22 Max. write data block length - * WRITE_BL_PARTIAL 21:21 Partial blocks for write allowed - * FILE_FORMAT_GROUP 15:15 File format group - * COPY 14:14 Copy flag (OTP) - * PERM_WRITE_PROTECT 13:13 Permanent write protection - * TMP_WRITE_PROTECT 12:12 Temporary write protection - * FILE_FORMAT 10:11 File format - * ECC 9:8 ECC (MMC only) - * CRC 7:1 CRC - * Not used 0:0 - */ - - permwriteprotect = (csd[3] >> 13) & 1; - tmpwriteprotect = (csd[3] >> 12) & 1; - priv->wrprotect = (permwriteprotect || tmpwriteprotect); - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) - decoded.wpgrpen = csd[3] >> 31; - decoded.mmcdfltecc = (csd[3] >> 29) & 3; - decoded.r2wfactor = (csd[3] >> 26) & 7; - decoded.writebllen = (csd[3] >> 22) & 0x0f; - decoded.writeblpartial = (csd[3] >> 21) & 1; - decoded.fileformatgrp = (csd[3] >> 15) & 1; - decoded.copy = (csd[3] >> 14) & 1; - decoded.permwriteprotect = permwriteprotect; - decoded.tmpwriteprotect = tmpwriteprotect; - decoded.fileformat = (csd[3] >> 10) & 3; - decoded.mmcecc = (csd[3] >> 8) & 3; - decoded.crc = (csd[3] >> 1) & 0x7f; - - fvdbg("CSD:\n"); - fvdbg(" CSD_STRUCTURE: %d SPEC_VERS: %d (MMC)\n", - decoded.csdstructure, decoded.mmcspecvers); - fvdbg(" TAAC {TIME_UNIT: %d TIME_VALUE: %d} NSAC: %d\n", - decoded.taac.timeunit, decoded.taac.timevalue, decoded.nsac); - fvdbg(" TRAN_SPEED {TRANSFER_RATE_UNIT: %d TIME_VALUE: %d}\n", - decoded.transpeed.transferrateunit, decoded.transpeed.timevalue); - fvdbg(" CCC: %d\n", decoded.ccc); - fvdbg(" READ_BL_LEN: %d READ_BL_PARTIAL: %d\n", - decoded.readbllen, decoded.readblpartial); - fvdbg(" WRITE_BLK_MISALIGN: %d READ_BLK_MISALIGN: %d\n", - decoded.writeblkmisalign, decoded.readblkmisalign); - fvdbg(" DSR_IMP: %d\n", - decoded.dsrimp); - - if (IS_BLOCK(priv->type)) - { - fvdbg(" SD Block Addressing:\n"); - fvdbg(" C_SIZE: %d SD_ER_BLK_EN: %d\n", - decoded.u.sdblock.csize, decoded.u.sdblock.sderblen); - fvdbg(" SD_SECTOR_SIZE: %d SD_WP_GRP_SIZE: %d\n", - decoded.u.sdblock.sdsectorsize, decoded.u.sdblock.sdwpgrpsize); - } - else if (IS_SD(priv->type)) - { - fvdbg(" SD Byte Addressing:\n"); - fvdbg(" C_SIZE: %d C_SIZE_MULT: %d\n", - decoded.u.sdbyte.csize, decoded.u.sdbyte.csizemult); - fvdbg(" VDD_R_CURR_MIN: %d VDD_R_CURR_MAX: %d\n", - decoded.u.sdbyte.vddrcurrmin, decoded.u.sdbyte.vddrcurrmax); - fvdbg(" VDD_W_CURR_MIN: %d VDD_W_CURR_MAX: %d\n", - decoded.u.sdbyte.vddwcurrmin, decoded.u.sdbyte.vddwcurrmax); - fvdbg(" SD_ER_BLK_EN: %d SD_SECTOR_SIZE: %d (SD) SD_WP_GRP_SIZE: %d\n", - decoded.u.sdbyte.sderblen, decoded.u.sdbyte.sdsectorsize, decoded.u.sdbyte.sdwpgrpsize); - } -#ifdef CONFIG_MMCSD_MMCSUPPORT - else if (IS_MMC(priv->type)) - { - fvdbg(" MMC:\n"); - fvdbg(" C_SIZE: %d C_SIZE_MULT: %d\n", - decoded.u.mmc.csize, decoded.u.mmc.csizemult); - fvdbg(" VDD_R_CURR_MIN: %d VDD_R_CURR_MAX: %d\n", - decoded.u.mmc.vddrcurrmin, decoded.u.mmc.vddrcurrmax); - fvdbg(" VDD_W_CURR_MIN: %d VDD_W_CURR_MAX: %d\n", - decoded.u.mmc.vddwcurrmin, decoded.u.mmc.vddwcurrmax); - fvdbg(" MMC_SECTOR_SIZE: %d MMC_ER_GRP_SIZE: %d MMC_WP_GRP_SIZE: %d\n", - decoded.u.mmc.er.mmc22.sectorsize, decoded.u.mmc.er.mmc22.ergrpsize, - decoded.u.mmc.mmcwpgrpsize); - } -#endif - - fvdbg(" WP_GRP_EN: %d MMC DFLT_ECC: %d (MMC) R2W_FACTOR: %d\n", - decoded.wpgrpen, decoded.mmcdfltecc, decoded.r2wfactor); - fvdbg(" WRITE_BL_LEN: %d WRITE_BL_PARTIAL: %d\n", - decoded.writebllen, decoded.writeblpartial); - fvdbg(" FILE_FORMAT_GROUP: %d COPY: %d\n", - decoded.fileformatgrp, decoded.copy); - fvdbg(" PERM_WRITE_PROTECT: %d TMP_WRITE_PROTECT: %d\n", - decoded.permwriteprotect, decoded.tmpwriteprotect); - fvdbg(" FILE_FORMAT: %d ECC: %d (MMC) CRC: %d\n", - decoded.fileformat, decoded.mmcecc, decoded.crc); - - fvdbg("Capacity: %luKb, Block size: %db, nblocks: %d wrprotect: %d\n", - (unsigned long)(priv->capacity / 1024), priv->blocksize, - priv->nblocks, priv->wrprotect); -#endif -} - -/**************************************************************************** - * Name: mmcsd_decodeCID - * - * Description: - * Show the contents of the Card Indentification Data (CID) (for debug - * purposes only) - * - ****************************************************************************/ - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -static void mmcsd_decodeCID(FAR struct mmcsd_state_s *priv, uint32_t cid[4]) -{ - struct mmcsd_cid_s decoded; - - /* Word 1: Bits 127-96: - * mid - 127-120 8-bit Manufacturer ID - * oid - 119-104 16-bit OEM/Application ID (ascii) - * pnm - 103-64 40-bit Product Name (ascii) + null terminator - * pnm[0] 103:96 - */ - - decoded.mid = cid[0] >> 24; - decoded.oid = (cid[0] >> 16) & 0xffff; - decoded.pnm[0] = cid[0] & 0xff; - - /* Word 2: Bits 64:95 - * pnm - 103-64 40-bit Product Name (ascii) + null terminator - * pnm[1] 95:88 - * pnm[2] 87:80 - * pnm[3] 79:72 - * pnm[4] 71:64 - */ - - decoded.pnm[1] = cid[1] >> 24; - decoded.pnm[2] = (cid[1] >> 16) & 0xff; - decoded.pnm[3] = (cid[1] >> 8) & 0xff; - decoded.pnm[4] = cid[1] & 0xff; - decoded.pnm[5] = '\0'; - - /* Word 3: Bits 32-63 - * prv - 63-56 8-bit Product revision - * psn - 55-24 32-bit Product serial number - */ - - decoded.prv = cid[2] >> 24; - decoded.psn = cid[2] << 8; - - /* Word 4: Bits 0-31 - * psn - 55-24 32-bit Product serial number - * 23-20 4-bit (reserved) - * mdt - 19:8 12-bit Manufacturing date - * crc - 7:1 7-bit CRC7 - */ - - decoded.psn |= cid[3] >> 24; - decoded.mdt = (cid[3] >> 8) & 0x0fff; - decoded.crc = (cid[3] >> 1) & 0x7f; - - fvdbg("mid: %02x oid: %04x pnm: %s prv: %d psn: %d mdt: %02x crc: %02x\n", - decoded.mid, decoded.oid, decoded.pnm, decoded.prv, - decoded.psn, decoded.mdt, decoded.crc); -} -#endif - -/**************************************************************************** - * Name: mmcsd_decodeSCR - * - * Description: - * Show the contents of the SD Configuration Register (SCR). The only - * value retained is: priv->buswidth; - * - ****************************************************************************/ - -static void mmcsd_decodeSCR(FAR struct mmcsd_state_s *priv, uint32_t scr[2]) -{ -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -struct mmcsd_scr_s decoded; -#endif - - /* Word 1, bits 63:32 - * SCR_STRUCTURE 63:60 4-bit SCR structure version - * SD_VERSION 59:56 4-bit SD memory spec. version - * DATA_STATE_AFTER_ERASE 55:55 1-bit erase status - * SD_SECURITY 54:52 3-bit SD security support level - * SD_BUS_WIDTHS 51:48 4-bit bus width indicator - * Reserved 47:32 16-bit SD reserved space - */ - -#ifdef CONFIG_ENDIAN_BIG /* Card transfers SCR in big-endian order */ - priv->buswidth = (scr[0] >> 16) & 15; -#else - priv->buswidth = (scr[0] >> 8) & 15; -#endif - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -#ifdef CONFIG_ENDIAN_BIG /* Card SCR is big-endian order / CPU also big-endian - * 60 56 52 48 44 40 36 32 - * VVVV SSSS ESSS BBBB RRRR RRRR RRRR RRRR */ - decoded.scrversion = scr[0] >> 28; - decoded.sdversion = (scr[0] >> 24) & 15; - decoded.erasestate = (scr[0] >> 23) & 1; - decoded.security = (scr[0] >> 20) & 7; -#else /* Card SCR is big-endian order / CPU is little-endian - * 36 32 44 40 52 48 60 56 - * RRRR RRRR RRRR RRRR ESSS BBBB VVVV SSSS */ - decoded.scrversion = (scr[0] >> 4) & 15; - decoded.sdversion = scr[0] & 15; - decoded.erasestate = (scr[0] >> 15) & 1; - decoded.security = (scr[0] >> 12) & 7; -#endif - decoded.buswidth = priv->buswidth; -#endif - - /* Word 1, bits 63:32 - * Reserved 31:0 32-bits reserved for manufacturing usage. - */ - -#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) - decoded.mfgdata = scr[1]; /* Might be byte reversed! */ - - fvdbg("SCR:\n"); - fvdbg(" SCR_STRUCTURE: %d SD_VERSION: %d\n", - decoded.scrversion,decoded.sdversion); - fvdbg(" DATA_STATE_AFTER_ERASE: %d SD_SECURITY: %d SD_BUS_WIDTHS: %x\n", - decoded.erasestate, decoded.security, decoded.buswidth); - fvdbg(" Manufacturing data: %08x\n", - decoded.mfgdata); -#endif -} - -/**************************************************************************** - * Name: mmcsd_getR1 - * - * Description: - * Get the R1 status of the card using CMD13 - * - ****************************************************************************/ - -static int mmcsd_getR1(FAR struct mmcsd_state_s *priv, FAR uint32_t *r1) -{ - uint32_t localR1; - int ret; - - DEBUGASSERT(priv != NULL && r1 != NULL); - - /* Send CMD13, SEND_STATUS. The addressed card responds by sending its - * R1 card status register. - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD13, (uint32_t)priv->rca << 16); - ret = SDIO_RECVR1(priv->dev, MMCSD_CMD13, &localR1); - if (ret == OK) - { - /* Check if R1 reports an error */ - - if ((localR1 & MMCSD_R1_ERRORMASK) != 0) - { - /* Card locked is considered an error. Save the card locked - * indication for later use. - */ - - priv->locked = ((localR1 & MMCSD_R1_CARDISLOCKED) != 0); - ret = -EIO; - } - else - { - /* No errors, return R1 */ - - *r1 = localR1; - } - } - return ret; -} - -/**************************************************************************** - * Name: mmcsd_verifystate - * - * Description: - * Verify that the card is in STANDBY state - * - ****************************************************************************/ - -static int mmcsd_verifystate(FAR struct mmcsd_state_s *priv, uint32_t state) -{ - uint32_t r1; - int ret; - - /* Get the current R1 status from the card */ - - ret = mmcsd_getR1(priv, &r1); - if (ret != OK) - { - fdbg("ERROR: mmcsd_getR1 failed: %d\n", ret); - return ret; - } - - /* Now check if the card is in the expected state. */ - - if (IS_STATE(r1, state)) - { - /* Yes.. return Success */ - - priv->wrbusy = false; - return OK; - } - return -EINVAL; -} - -/**************************************************************************** - * Transfer Helpers - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_wrprotected - * - * Description: - * Return true if the the card is unlocked an not write protected. The - * - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv) -{ - /* Check if the card is locked (priv->locked) or write protected either (1) - * via software as reported via the CSD and retained in priv->wrprotect or - * (2) via the mechanical write protect on the card (which we get from the - * SDIO driver via SDIO_WRPROTECTED) - */ - - return (priv->wrprotect || priv->locked || SDIO_WRPROTECTED(priv->dev)); -} -#endif - -/**************************************************************************** - * Name: mmcsd_eventwait - * - * Description: - * Wait for the specified events to occur. Check for wakeup on error events. - * - ****************************************************************************/ - -static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv, - sdio_eventset_t failevents, uint32_t timeout) -{ - sdio_eventset_t wkupevent; - - /* Wait for the set of events enabled by SDIO_EVENTENABLE. */ - - wkupevent = SDIO_EVENTWAIT(priv->dev, timeout); - - /* SDIO_EVENTWAIT returns the event set containing the event(s) that ended - * the wait. It should always be non-zero, but may contain failure as - * well as success events. Check if it contains any failure events. - */ - - if ((wkupevent & failevents) != 0) - { - /* Yes.. the failure event is probably SDIOWAIT_TIMEOUT */ - - fdbg("ERROR: Awakened with %02x\n", wkupevent); - return wkupevent & SDIOWAIT_TIMEOUT ? -ETIMEDOUT : -EIO; - } - - /* Since there are no failure events, we must have been awakened by one - * (or more) success events. - */ - - return OK; -} - -/**************************************************************************** - * Name: mmcsd_transferready - * - * Description: - * Check if the MMC/SD card is ready for the next read or write transfer. - * Ready means: (1) card still in the slot, and (2) if the last transfer - * was a write transfer, the card is no longer busy from that transfer. - * - ****************************************************************************/ - -static int mmcsd_transferready(FAR struct mmcsd_state_s *priv) -{ - uint32_t starttime; - uint32_t elapsed; - uint32_t r1; - int ret; - - /* First, check if the card has been removed. */ - - if (!SDIO_PRESENT(priv->dev)) - { - fdbg("ERROR: Card has been removed\n"); - return -ENODEV; - } - - /* If the last data transfer was not a write, then we do not have to check - * the card status. - */ - - else if (!priv->wrbusy) - { - return OK; - } - - /* The card is still present and the last transfer was a write transfer. - * Loop, querying the card state. Return when (1) the card is in the TRANSFER - * state, (2) the card stays in the PROGRAMMING state too long, or (3) the - * card is in any other state. - * - * The PROGRAMMING state occurs normally after a WRITE operation. During this - * time, the card may be busy completing the WRITE and is not available for - * other operations. The card will transition from the PROGRAMMING state to - * the TRANSFER state when the card completes the WRITE operation. - */ - - starttime = clock_systimer(); - do - { - /* Get the current R1 status from the card */ - - ret = mmcsd_getR1(priv, &r1); - if (ret != OK) - { - fdbg("ERROR: mmcsd_getR1 failed: %d\n", ret); - return ret; - } - - /* Now check if the card is in the expected transfer state. */ - - if (IS_STATE(r1, MMCSD_R1_STATE_TRAN)) - { - /* Yes.. return Success */ - - priv->wrbusy = false; - return OK; - } - - /* Check for the programming state. This is not an error. It means - * that the card is still busy from the last (write) transfer. - */ - - else if (!IS_STATE(r1, MMCSD_R1_STATE_PRG)) - { - /* Any other state would be an error in this context. There is - * a possibility that the card is not selected. In this case, - * it could be in STANDBY or DISCONNECTED state and the fix - * might b to send CMD7 to re-select the card. Consider this - * if this error occurs. - */ - - fdbg("ERROR: Unexpected R1 state: %08x\n", r1); - return -EINVAL; - } - - /* We are still in the programming state. Calculate the elapsed - * time... we can't stay in this loop forever! - */ - - elapsed = clock_systimer() - starttime; - } - while (elapsed < TICK_PER_SEC); - return -ETIMEDOUT; -} - -/**************************************************************************** - * Name: mmcsd_stoptransmission - * - * Description: - * Send STOP_TRANSMISSION - * - ****************************************************************************/ - -#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE -static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv) -{ - int ret; - - /* Send CMD12, STOP_TRANSMISSION, and verify good R1 return status */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD12, 0); - ret = mmcsd_recvR1(priv, MMCSD_CMD12); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for CMD12 failed: %d\n", ret); - } - return ret; -} -#endif - -/**************************************************************************** - * Name: mmcsd_setblocklen - * - * Description: - * Read a single block of data. - * - ****************************************************************************/ - -static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv, uint32_t blocklen) -{ - int ret = OK; - - /* Is the block length already selected in the card? */ - - if (priv->selblocklen != blocklen) - { - /* Send CMD16 = SET_BLOCKLEN. This command sets the block length (in - * bytes) for all following block commands (read and write). Default - * block length is specified in the CSD. - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD16, blocklen); - ret = mmcsd_recvR1(priv, MMCSD_CMD16); - if (ret == OK) - { - priv->selblocklen = blocklen; - } - else - { - fdbg("ERROR: mmcsd_recvR1 for CMD16 failed: %d\n", ret); - } - } - - return ret; -} - -/**************************************************************************** - * Name: mmcsd_readsingle - * - * Description: - * Read a single block of data. - * - ****************************************************************************/ - -static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, - FAR uint8_t *buffer, off_t startblock) -{ - off_t offset; - int ret; - - fvdbg("startblock=%d\n", startblock); - DEBUGASSERT(priv != NULL && buffer != NULL); - - /* Check if the card is locked */ - - if (priv->locked) - { - fdbg("ERROR: Card is locked\n"); - return -EPERM; - } - - /* Verify that the card is ready for the transfer. The card may still be - * busy from the preceding write transfer. It would be simpler to check - * for write busy at the end of each write, rather than at the beginning of - * each read AND write, but putting the busy-wait at the beginning of the - * transfer allows for more overlap and, hopefully, better performance - */ - - ret = mmcsd_transferready(priv); - if (ret != OK) - { - fdbg("ERROR: Card not ready: %d\n", ret); - return ret; - } - - /* If this is a byte addressed SD card, then convert sector start sector - * number to a byte offset - */ - - if (IS_BLOCK(priv->type)) - { - offset = startblock; - } - else - { - offset = startblock << priv->blockshift; - } - fvdbg("offset=%d\n", offset); - - /* Select the block size for the card */ - - ret = mmcsd_setblocklen(priv, priv->blocksize); - if (ret != OK) - { - fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret); - return ret; - } - - /* Configure SDIO controller hardware for the read transfer */ - - SDIO_BLOCKSETUP(priv->dev, priv->blocksize, 1); - SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR); -#ifdef CONFIG_SDIO_DMA - if (priv->dma) - { - SDIO_DMARECVSETUP(priv->dev, buffer, priv->blocksize); - } - else -#endif - { - SDIO_RECVSETUP(priv->dev, buffer, priv->blocksize); - } - - /* Send CMD17, READ_SINGLE_BLOCK: Read a block of the size selected - * by the mmcsd_setblocklen() and verify that good R1 status is - * returned. The card state should change from Transfer to Sending-Data - * state. - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD17, offset); - ret = mmcsd_recvR1(priv, MMCSD_CMD17); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for CMD17 failed: %d\n", ret); - SDIO_CANCEL(priv->dev); - return ret; - } - - /* Then wait for the data transfer to complete */ - - ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, MMCSD_BLOCK_DATADELAY); - if (ret != OK) - { - fdbg("ERROR: CMD17 transfer failed: %d\n", ret); - return ret; - } - - /* Return value: One sector read */ - - return 1; -} - -/**************************************************************************** - * Name: mmcsd_readmultiple - * - * Description: - * Read multiple, contiguous blocks of data from the physical device. - * - ****************************************************************************/ - -#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE -static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, - FAR uint8_t *buffer, off_t startblock, - size_t nblocks) -{ - size_t nbytes; - off_t offset; - int ret; - - fvdbg("startblock=%d nblocks=%d\n", startblock, nblocks); - DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 1); - - /* Check if the card is locked */ - - if (priv->locked) - { - fdbg("ERROR: Card is locked\n"); - return -EPERM; - } - - /* Verify that the card is ready for the transfer. The card may still be - * busy from the preceding write transfer. It would be simpler to check - * for write busy at the end of each write, rather than at the beginning of - * each read AND write, but putting the busy-wait at the beginning of the - * transfer allows for more overlap and, hopefully, better performance - */ - - ret = mmcsd_transferready(priv); - if (ret != OK) - { - fdbg("ERROR: Card not ready: %d\n", ret); - return ret; - } - - /* If this is a byte addressed SD card, then convert both the total transfer - * size to bytes and the sector start sector number to a byte offset - */ - - nbytes = nblocks << priv->blockshift; - if (IS_BLOCK(priv->type)) - { - offset = startblock; - } - else - { - offset = startblock << priv->blockshift; - } - fvdbg("nbytes=%d byte offset=%d\n", nbytes, offset); - - /* Select the block size for the card */ - - ret = mmcsd_setblocklen(priv, priv->blocksize); - if (ret != OK) - { - fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret); - return ret; - } - - /* Configure SDIO controller hardware for the read transfer */ - - SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks); - SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR); -#ifdef CONFIG_SDIO_DMA - if (priv->dma) - { - SDIO_DMARECVSETUP(priv->dev, buffer, nbytes); - } - else -#endif - { - SDIO_RECVSETUP(priv->dev, buffer, nbytes); - } - - /* Send CMD18, READ_MULT_BLOCK: Read a block of the size selected by - * the mmcsd_setblocklen() and verify that good R1 status is returned - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD18, offset); - ret = mmcsd_recvR1(priv, MMCSD_CMD18); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for CMD18 failed: %d\n", ret); - SDIO_CANCEL(priv->dev); - return ret; - } - - /* Wait for the transfer to complete */ - - ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, nblocks * MMCSD_BLOCK_DATADELAY); - if (ret != OK) - { - fdbg("ERROR: CMD18 transfer failed: %d\n", ret); - return ret; - } - - /* Send STOP_TRANSMISSION */ - - ret = mmcsd_stoptransmission(priv); - if (ret != OK) - { - fdbg("ERROR: mmcsd_stoptransmission failed: %d\n", ret); - } - - /* On success, return the number of blocks read */ - - return nblocks; -} -#endif - -/**************************************************************************** - * Name: mmcsd_reload - * - * Description: - * Reload the specified number of sectors from the physical device into the - * read-ahead buffer. - * - ****************************************************************************/ - -#ifdef CONFIG_FS_READAHEAD -static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, - off_t startblock, size_t nblocks) -{ - FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev; -#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE - size_t block; - size_t endblock; -#endif - ssize_t ret; - - DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0) - -#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE - /* Read each block using only the single block transfer method */ - - endblock = startblock + nblocks - 1; - for (block = startblock; block <= endblock; block++) - { - /* Read this block into the user buffer */ - - ret = mmcsd_readsingle(priv, buffer, block); - if (ret < 0) - { - break; - } - - /* Increment the buffer pointer by the block size */ - - buffer += priv->blocksize; - } -#else - /* Use either the single- or muliple-block transfer method */ - - if (nblocks == 1) - { - ret = mmcsd_readsingle(priv, buffer, startblock); - } - else - { - ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks); - } -#endif - - /* On success, return the number of blocks read */ - - return ret; -} -#endif - -/**************************************************************************** - * Name: mmcsd_writesingle - * - * Description: - * Write a single block of data to the physical device. - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, - FAR const uint8_t *buffer, off_t startblock) -{ - off_t offset; - int ret; - - fvdbg("startblock=%d\n", startblock); - DEBUGASSERT(priv != NULL && buffer != NULL); - - /* Check if the card is locked or write protected (either via software or - * via the mechanical write protect on the card) - */ - - if (mmcsd_wrprotected(priv)) - { - fdbg("ERROR: Card is locked or write protected\n"); - return -EPERM; - } - - /* Verify that the card is ready for the transfer. The card may still be - * busy from the preceding write transfer. It would be simpler to check - * for write busy at the end of each write, rather than at the beginning of - * each read AND write, but putting the busy-wait at the beginning of the - * transfer allows for more overlap and, hopefully, better performance - */ - - ret = mmcsd_transferready(priv); - if (ret != OK) - { - fdbg("ERROR: Card not ready: %d\n", ret); - return ret; - } - - /* If this is a byte addressed SD card, then convert sector start sector - * number to a byte offset - */ - - if (IS_BLOCK(priv->type)) - { - offset = startblock; - } - else - { - offset = startblock << priv->blockshift; - } - fvdbg("offset=%d\n", offset); - - /* Select the block size for the card */ - - ret = mmcsd_setblocklen(priv, priv->blocksize); - if (ret != OK) - { - fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret); - return ret; - } - - /* Send CMD24, WRITE_BLOCK, and verify that good R1 status is returned */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD24, offset); - ret = mmcsd_recvR1(priv, MMCSD_CMD24); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for CMD24 failed: %d\n", ret); - return ret; - } - - /* Configure SDIO controller hardware for the write transfer */ - - SDIO_BLOCKSETUP(priv->dev, priv->blocksize, 1); - SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR); -#ifdef CONFIG_SDIO_DMA - if (priv->dma) - { - SDIO_DMASENDSETUP(priv->dev, buffer, priv->blocksize); - } - else -#endif - { - SDIO_SENDSETUP(priv->dev, buffer, priv->blocksize); - } - - /* Flag that a write transfer is pending that we will have to check for - * write complete at the beginning of the next transfer. - */ - - priv->wrbusy = true; - - /* Wait for the transfer to complete */ - - ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, MMCSD_BLOCK_DATADELAY); - if (ret != OK) - { - fdbg("ERROR: CMD24 transfer failed: %d\n", ret); - return ret; - } - - /* On success, return the number of blocks written */ - - return 1; -} -#endif - -/**************************************************************************** - * Name: mmcsd_writemultiple - * - * Description: - * Write multiple, contiguous blocks of data to the physical device. - * - ****************************************************************************/ - -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) -static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, - FAR const uint8_t *buffer, off_t startblock, - size_t nblocks) -{ - off_t offset; - size_t nbytes; - int ret; - - fvdbg("startblockr=%d nblocks=%d\n", startblock, nblocks); - DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 1); - - /* Check if the card is locked or write protected (either via software or - * via the mechanical write protect on the card) - */ - - if (mmcsd_wrprotected(priv)) - { - fdbg("ERROR: Card is locked or write protected\n"); - return -EPERM; - } - - /* Verify that the card is ready for the transfer. The card may still be - * busy from the preceding write transfer. It would be simpler to check - * for write busy at the end of each write, rather than at the beginning of - * each read AND write, but putting the busy-wait at the beginning of the - * transfer allows for more overlap and, hopefully, better performance - */ - - ret = mmcsd_transferready(priv); - if (ret != OK) - { - fdbg("ERROR: Card not ready: %d\n", ret); - return ret; - } - - /* If this is a byte addressed SD card, then convert both the total transfer - * size to bytes and the sector start sector number to a byte offset - */ - - nbytes = nblocks << priv->blockshift; - if (IS_BLOCK(priv->type)) - { - offset = startblock; - } - else - { - offset = startblock << priv->blockshift; - } - fvdbg("nbytes=%d byte offset=%d\n", nbytes, offset); - - /* Select the block size for the card */ - - ret = mmcsd_setblocklen(priv, priv->blocksize); - if (ret != OK) - { - fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret); - return ret; - } - - /* If this is an SD card, then send ACMD23 (SET_WR_BLK_COUNT) just before - * sending CMD25 (WRITE_MULTIPLE_BLOCK). This sets the number of write - * blocks to be pre-erased and might make the following multiple block write - * command faster. - */ - - if (IS_SD(priv->type)) - { - /* Send CMD55, APP_CMD, a verify that good R1 status is retured */ - - mmcsd_sendcmdpoll(priv, SD_CMD55, 0); - ret = mmcsd_recvR1(priv, SD_CMD55); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for CMD55 (ACMD23) failed: %d\n", ret); - return ret; - } - - /* Send CMD23, SET_WR_BLK_COUNT, and verify that good R1 status is returned */ - - mmcsd_sendcmdpoll(priv, SD_ACMD23, 0); - ret = mmcsd_recvR1(priv, SD_ACMD23); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for ACMD23 failed: %d\n", ret); - return ret; - } - } - - /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status - * is returned - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset); - ret = mmcsd_recvR1(priv, MMCSD_CMD25); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for CMD24 failed: %d\n", ret); - return ret; - } - - /* Configure SDIO controller hardware for the write transfer */ - - SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks); - SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR); -#ifdef CONFIG_SDIO_DMA - if (priv->dma) - { - SDIO_DMASENDSETUP(priv->dev, buffer, nbytes); - } - else -#endif - { - SDIO_SENDSETUP(priv->dev, buffer, nbytes); - } - - /* Flag that a write transfer is pending that we will have to check for - * write complete at the beginning of the next transfer. - */ - - priv->wrbusy = true; - - /* Wait for the transfer to complete */ - - ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, nblocks * MMCSD_BLOCK_DATADELAY); - if (ret != OK) - { - fdbg("ERROR: CMD18 transfer failed: %d\n", ret); - return ret; - } - - /* Send STOP_TRANSMISSION */ - - ret = mmcsd_stoptransmission(priv); - if (ret != OK) - { - fdbg("ERROR: mmcsd_stoptransmission failed: %d\n", ret); - return ret; - } - - /* On success, return the number of blocks read */ - - return nblocks; -} -#endif - -/**************************************************************************** - * Name: mmcsd_flush - * - * Description: - * Flush the specified number of sectors from the write buffer to the card. - * - ****************************************************************************/ - -#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER) -static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, - off_t startblock, size_t nblocks) -{ - FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev; -#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE - size_t block; - size_t endblock; -#endif - ssize_t ret; - - DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0) - -#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE - /* Write each block using only the single block transfer method */ - - endblock = startblock + nblocks - 1; - for (block = startblock; block <= endblock; block++) - { - /* Write this block from the user buffer */ - - ret = mmcsd_writesingle(priv, buffer, block); - if (ret < 0) - { - break; - } - - /* Increment the buffer pointer by the block size */ - - buffer += priv->blocksize; - } -#else - if (nblocks == 1) - { - ret = mmcsd_writesingle(priv, buffer, startblock); - } - else - { - ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks); - } -#endif - - /* On success, return the number of blocks written */ - - return ret; -} -#endif - -/**************************************************************************** - * Block Driver Methods - ****************************************************************************/ -/**************************************************************************** - * Name: mmcsd_open - * - * Description: Open the block device - * - ****************************************************************************/ - -static int mmcsd_open(FAR struct inode *inode) -{ - FAR struct mmcsd_state_s *priv; - - fvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct mmcsd_state_s *)inode->i_private; - - /* Just increment the reference count on the driver */ - - DEBUGASSERT(priv->crefs < MAX_CREFS); - mmcsd_takesem(priv); - priv->crefs++; - mmcsd_givesem(priv); - return OK; -} - -/**************************************************************************** - * Name: mmcsd_close - * - * Description: close the block device - * - ****************************************************************************/ - -static int mmcsd_close(FAR struct inode *inode) -{ - FAR struct mmcsd_state_s *priv; - - fvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct mmcsd_state_s *)inode->i_private; - - /* Decrement the reference count on the block driver */ - - DEBUGASSERT(priv->crefs > 0); - mmcsd_takesem(priv); - priv->crefs--; - mmcsd_givesem(priv); - return OK; -} - -/**************************************************************************** - * Name: mmcsd_read - * - * Description: - * Read the specified numer of sectors from the read-ahead buffer or from - * the physical device. - * - ****************************************************************************/ - -static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, - size_t startsector, unsigned int nsectors) -{ - FAR struct mmcsd_state_s *priv; -#if !defined(CONFIG_FS_READAHEAD) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) - size_t sector; - size_t endsector; -#endif - ssize_t ret = 0; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct mmcsd_state_s *)inode->i_private; - fvdbg("startsector: %d nsectors: %d sectorsize: %d\n", - startsector, nsectors, priv->blocksize); - - if (nsectors > 0) - { - mmcsd_takesem(priv); - -#if defined(CONFIG_FS_READAHEAD) - /* Get the data from the read-ahead buffer */ - - ret = rwb_read(&priv->rwbuffer, startsector, nsectors, buffer); - -#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) - /* Read each block using only the single block transfer method */ - - endsector = startsector + nsectors - 1; - for (sector = startsector; sector <= endsector; sector++) - { - /* Read this sector into the user buffer */ - - ret = mmcsd_readsingle(priv, buffer, sector); - if (ret < 0) - { - break; - } - - /* Increment the buffer pointer by the sector size */ - - buffer += priv->blocksize; - } -#else - /* Use either the single- or muliple-block transfer method */ - - if (nsectors == 1) - { - ret = mmcsd_readsingle(priv, buffer, startsector); - } - else - { - ret = mmcsd_readmultiple(priv, buffer, startsector, nsectors); - } -#endif - mmcsd_givesem(priv); - } - - /* On success, return the number of blocks read */ - - return ret; -} - -/**************************************************************************** - * Name: mmcsd_write - * - * Description: - * Write the specified number of sectors to the write buffer or to the - * physical device. - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buffer, - size_t startsector, unsigned int nsectors) -{ - FAR struct mmcsd_state_s *priv; -#if !defined(CONFIG_FS_WRITEBUFFER) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) - size_t sector; - size_t endsector; -#endif - ssize_t ret = 0; - - fvdbg("sector: %d nsectors: %d sectorsize: %d\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct mmcsd_state_s *)inode->i_private; - - mmcsd_takesem(priv); - -#if defined(CONFIG_FS_WRITEBUFFER) - /* Write the data to the write buffer */ - - ret = rwb_write(&priv->rwbuffer, startsector, nsectors, buffer); - -#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) - /* Write each block using only the single block transfer method */ - - endsector = startsector + nsectors - 1; - for (sector = startsector; sector <= endsector; sector++) - { - /* Write this block from the user buffer */ - - ret = mmcsd_writesingle(priv, buffer, sector); - if (ret < 0) - { - break; - } - - /* Increment the buffer pointer by the block size */ - - buffer += priv->blocksize; - } -#else - /* Use either the single- or multiple-block transfer method */ - - if (nsectors == 1) - { - ret = mmcsd_writesingle(priv, buffer, startsector); - } - else - { - ret = mmcsd_writemultiple(priv, buffer, startsector, nsectors); - } -#endif - mmcsd_givesem(priv); - - /* On success, return the number of blocks written */ - - return ret; -} -#endif - -/**************************************************************************** - * Name: mmcsd_geometry - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry) -{ - FAR struct mmcsd_state_s *priv; - int ret = -EINVAL; - - fvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - - if (geometry) - { - /* Is there a (supported) card inserted in the slot? */ - - priv = (FAR struct mmcsd_state_s *)inode->i_private; - mmcsd_takesem(priv); - if (IS_EMPTY(priv)) - { - /* No.. return ENODEV */ - - fvdbg("IS_EMPTY\n"); - ret = -ENODEV; - } - else - { - /* Yes.. return the geometry of the card */ - - geometry->geo_available = true; - geometry->geo_mediachanged = priv->mediachanged; -#ifdef CONFIG_FS_WRITABLE - geometry->geo_writeenabled = !mmcsd_wrprotected(priv); -#else - geometry->geo_writeenabled = false; -#endif - geometry->geo_nsectors = priv->nblocks; - geometry->geo_sectorsize = priv->blocksize; - - fvdbg("available: true mediachanged: %s writeenabled: %s\n", - geometry->geo_mediachanged ? "true" : "false", - geometry->geo_writeenabled ? "true" : "false"); - fvdbg("nsectors: %ld sectorsize: %d\n", - (long)geometry->geo_nsectors, geometry->geo_sectorsize); - - priv->mediachanged = false; - ret = OK; - } - mmcsd_givesem(priv); - } - - return ret; -} - -/**************************************************************************** - * Name: mmcsd_ioctl - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) -{ - FAR struct mmcsd_state_s *priv; - int ret; - - fvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct mmcsd_state_s *)inode->i_private; - - /* Process the IOCTL by command */ - - mmcsd_takesem(priv); - switch (cmd) - { - case BIOC_PROBE: /* Check for media in the slot */ - { - fvdbg("BIOC_PROBE\n"); - - /* Probe the MMC/SD slot for media */ - - ret = mmcsd_probe(priv); - if (ret != OK) - { - fdbg("ERROR: mmcsd_probe failed: %d\n", ret); - } - } - break; - - case BIOC_EJECT: /* Media has been removed from the slot */ - { - fvdbg("BIOC_EJECT\n"); - - /* Process the removal of the card */ - - ret = mmcsd_removed(priv); - if (ret != OK) - { - fdbg("ERROR: mmcsd_removed failed: %d\n", ret); - } - - /* Enable logic to detect if a card is re-inserted */ - - SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); - } - break; - - default: - ret = -ENOTTY; - break; - } - - mmcsd_givesem(priv); - return ret; -} - -/**************************************************************************** - * Initialization/uninitialization/reset - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_mediachange - * - * Description: - * This is a callback function from the SDIO driver that indicates that - * there has been a change in the slot... either a card has been inserted - * or a card has been removed. - * - * Assumptions: - * This callback is NOT supposd to run in the context of an interrupt - * handler; it is probably running in the context of work thread. - * - ****************************************************************************/ - -static void mmcsd_mediachange(FAR void *arg) -{ - FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)arg; - - fvdbg("arg: %p\n", arg); - DEBUGASSERT(priv); - - /* Is there a card present in the slot? */ - - mmcsd_takesem(priv); - if (SDIO_PRESENT(priv->dev)) - { - /* No... process the card insertion. This could cause chaos if we think - * that a card is already present and there are mounted filesystems! - * NOTE that mmcsd_probe() will always re-enable callbacks appropriately. - */ - - (void)mmcsd_probe(priv); - } - else - { - /* No... process the card removal. This could have very bad implications - * for any mounted file systems! NOTE that mmcsd_removed() does NOT - * re-enable callbacks so we will need to do that here. - */ - - (void)mmcsd_removed(priv); - - /* Enable logic to detect if a card is re-inserted */ - - SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); - } - mmcsd_givesem(priv); -} - -/**************************************************************************** - * Name: mmcsd_widebus - * - * Description: - * An SD card has been inserted and its SCR has been obtained. Select wide - * (4-bit) bus operation if the card supports it. - * - * Assumptions: - * This function is called only once per card insertion as part of the SD - * card initialization sequence. It is not necessary to reselect the card - * there is not need to check if wide bus operation has already been - * selected. - * - ****************************************************************************/ - -static int mmcsd_widebus(FAR struct mmcsd_state_s *priv) -{ -#ifndef CONFIG_SDIO_WIDTH_D1_ONLY - int ret; - - /* Check if the SD card supports this feature (as reported in the SCR) */ - - if ((priv->buswidth & MMCSD_SCR_BUSWIDTH_4BIT) != 0) - { - /* Disconnect any CD/DAT3 pull up using ACMD42. ACMD42 is optional and - * need not be supported by all SD calls. - * - * First end CMD55 APP_CMD with argument as card's RCA. - */ - - mmcsd_sendcmdpoll(priv, SD_CMD55, (uint32_t)priv->rca << 16); - ret = mmcsd_recvR1(priv, SD_CMD55); - if (ret != OK) - { - fdbg("ERROR: RECVR1 for CMD55 of ACMD42: %d\n", ret); - return ret; - } - - /* Then send ACMD42 with the argument to disconnect the CD/DAT3 - * pullup - */ - - mmcsd_sendcmdpoll(priv, SD_ACMD42, MMCSD_ACMD42_CD_DISCONNECT); - ret = mmcsd_recvR1(priv, SD_ACMD42); - if (ret != OK) - { - fvdbg("WARNING: SD card does not support ACMD42: %d\n", ret); - return ret; - } - - /* Now send ACMD6 to select wide, 4-bit bus operation, beginning - * with CMD55, APP_CMD: - */ - - mmcsd_sendcmdpoll(priv, SD_CMD55, (uint32_t)priv->rca << 16); - ret = mmcsd_recvR1(priv, SD_CMD55); - if (ret != OK) - { - fdbg("ERROR: RECVR1 for CMD55 of ACMD6: %d\n", ret); - return ret; - } - - /* Then send ACMD6 */ - - mmcsd_sendcmdpoll(priv, SD_ACMD6, MMCSD_ACMD6_BUSWIDTH_4); - ret = mmcsd_recvR1(priv, SD_ACMD6); - if (ret != OK) - { - return ret; - } - - /* Configure the SDIO peripheral */ - - fvdbg("Wide bus operation selected\n"); - SDIO_WIDEBUS(priv->dev, true); - priv->widebus = true; - - SDIO_CLOCK(priv->dev, CLOCK_SD_TRANSFER_4BIT); - up_udelay(MMCSD_CLK_DELAY); - return OK; - } - - /* Wide bus operation not supported */ - - fdbg("WARNING: Card does not support wide-bus operation\n"); - return -ENOSYS; - -#else /* CONFIG_SDIO_WIDTH_D1_ONLY */ - - fvdbg("Wide-bus operation is disabled\n"); - return -ENOSYS; - -#endif /* CONFIG_SDIO_WIDTH_D1_ONLY */ -} - -/**************************************************************************** - * Name: mmcsd_mmcinitialize - * - * Description: - * We believe that there is an MMC card in the slot. Attempt to initialize - * and configure the MMC card. This is called only from mmcsd_probe(). - * - ****************************************************************************/ - -#ifdef CONFIG_MMCSD_MMCSUPPORT -static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) -{ - uint32_t cid[4]; - uint32_t csd[4]; - int ret; - - /* At this point, slow, ID mode clocking has been supplied to the card - * and CMD0 has been sent successfully. CMD1 succeeded and ACMD41 failed - * so there is good evidence that we have an MMC card inserted into the - * slot. - * - * Send CMD2, ALL_SEND_CID. This implementation supports only one MMC slot. - * If mulitple cards were installed, each card would respond to CMD2 by - * sending its CID (only one card completes the response at a time). The - * driver should send CMD2 and assign an RCAs until no response to - * ALL_SEND_CID is received. CMD2 causes transition to identification state/ - * card-identification mode */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD2, 0); - ret = SDIO_RECVR2(priv->dev, MMCSD_CMD2, cid); - if (ret != OK) - { - fdbg("ERROR: SDIO_RECVR2 for MMC CID failed: %d\n", ret); - return ret; - } - mmcsd_decodeCID(priv, cid); - - /* Send CMD3, SET_RELATIVE_ADDR. This command is used to assign a logical - * address to the card. For MMC, the host assigns the address. CMD3 causes - * transition to standby state/data-transfer mode - */ - - priv->rca = 1; /* There is only one card */ - mmcsd_sendcmdpoll(priv, MMC_CMD3, priv->rca << 16); - ret = mmcsd_recvR1(priv, MMC_CMD3); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1(CMD3) failed: %d\n", ret); - return ret; - } - - /* This should have caused a transition to standby state. However, this will - * not be reflected in the present R1 status. R1/6 contains the state of the - * card when the command was received, not when it completed execution. - * - * Verify that we are in standby state/data-transfer mode - */ - - ret = mmcsd_verifystate(priv, MMCSD_R1_STATE_STBY); - if (ret != OK) - { - fdbg("ERROR: Failed to enter standby state\n"); - return ret; - } - - /* Send CMD9, SEND_CSD in standby state/data-transfer mode to obtain the - * Card Specific Data (CSD) register, e.g., block length, card storage - * capacity, etc. (Stays in standy state/data-transfer mode) - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD9, priv->rca << 16); - ret = SDIO_RECVR2(priv->dev, MMCSD_CMD9, csd); - if (ret != OK) - { - fdbg("ERROR: Could not get SD CSD register: %d\n", ret); - return ret; - } - mmcsd_decodeCSD(priv, csd); - - /* Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been - * provided and (2) the card supports a DSR register. If no DSR value - * the card default value (0x0404) will be used. - */ - - (void)mmcsd_sendcmd4(priv); - - /* Select high speed MMC clocking (which may depend on the DSR setting) */ - - SDIO_CLOCK(priv->dev, CLOCK_MMC_TRANSFER); - up_udelay(MMCSD_CLK_DELAY); - return OK; -} -#endif - -/**************************************************************************** - * Name: mmcsd_sdinitialize - * - * Description: - * We believe that there is an SD card in the slot. Attempt to initialize - * and configure the SD card. This is called only from mmcsd_probe(). - * - ****************************************************************************/ - -static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv) -{ - uint32_t cid[4]; - uint32_t csd[4]; - uint32_t scr[2]; - int ret; - - /* At this point, clocking has been supplied to the card, both CMD0 and - * ACMD41 (with OCR=0) have been sent successfully, the card is no longer - * busy and (presumably) in the IDLE state so there is good evidence - * that we have an SD card inserted into the slot. - * - * Send CMD2, ALL_SEND_CID. The SD CMD2 is similar to the MMC CMD2 except - * that the buffer type used to transmit to response of the card (SD Memory - * Card: Push-Pull, MMC: Open-Drain). This implementation supports only a - * single SD card. If multiple cards were installed in the slot, each card - * would respond to CMD2 by sending its CID (only one card completes the - * response at a time). The driver should send CMD2 and obtain RCAs until - * no response to ALL_SEND_CID is received. - * - * When an SD card receives the CMD2 command it should transition to the - * identification state/card-identification mode - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD2, 0); - ret = SDIO_RECVR2(priv->dev, MMCSD_CMD2, cid); - if (ret != OK) - { - fdbg("ERROR: SDIO_RECVR2 for SD CID failed: %d\n", ret); - return ret; - } - mmcsd_decodeCID(priv, cid); - - /* Send CMD3, SET_RELATIVE_ADDR. In both protocols, this command is used - * to assign a logical address to the card. For MMC, the host assigns the - * address; for SD, the memory card has this responsibility. CMD3 causes - * transition to standby state/data-transfer mode - * - * Send CMD3 with argument 0, SD card publishes its RCA in the response. - */ - - mmcsd_sendcmdpoll(priv, SD_CMD3, 0); - ret = mmcsd_recvR6(priv, SD_CMD3); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR2 for SD RCA failed: %d\n", ret); - return ret; - } - fvdbg("RCA: %04x\n", priv->rca); - - /* This should have caused a transition to standby state. However, this will - * not be reflected in the present R1 status. R1/6 contains the state of - * the card when the command was received, not when it completed execution. - * - * Verify that we are in standby state/data-transfer mode - */ - - ret = mmcsd_verifystate(priv, MMCSD_R1_STATE_STBY); - if (ret != OK) - { - fdbg("ERROR: Failed to enter standby state\n"); - return ret; - } - - /* Send CMD9, SEND_CSD, in standby state/data-transfer mode to obtain the - * Card Specific Data (CSD) register. The argument is the RCA that we - * just obtained from CMD3. The card stays in standy state/data-transfer - * mode. - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD9, (uint32_t)priv->rca << 16); - ret = SDIO_RECVR2(priv->dev, MMCSD_CMD9, csd); - if (ret != OK) - { - fdbg("ERROR: Could not get SD CSD register(%d)\n", ret); - return ret; - } - mmcsd_decodeCSD(priv, csd); - - /* Send CMD7 with the argument == RCA in order to select the card. - * Since we are supporting only a single card, we just leave the - * card selected all of the time. - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD7S, (uint32_t)priv->rca << 16); - ret = mmcsd_recvR1(priv, MMCSD_CMD7S); - if (ret != OK) - { - fdbg("ERROR: mmcsd_recvR1 for CMD7 failed: %d\n", ret); - return ret; - } - - /* Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been - * provided and (2) the card supports a DSR register. If no DSR value - * the card default value (0x0404) will be used. - */ - - (void)mmcsd_sendcmd4(priv); - - /* Select high speed SD clocking (which may depend on the DSR setting) */ - - SDIO_CLOCK(priv->dev, CLOCK_SD_TRANSFER_1BIT); - up_udelay(MMCSD_CLK_DELAY); - - /* Get the SD card Configuration Register (SCR). We need this now because - * that configuration register contains the indication whether or not - * this card supports wide bus operation. - */ - - ret = mmcsd_getSCR(priv, scr); - if (ret != OK) - { - fdbg("ERROR: Could not get SD SCR register(%d)\n", ret); - return ret; - } - mmcsd_decodeSCR(priv, scr); - - /* Select width (4-bit) bus operation (if the card supports it) */ - - ret = mmcsd_widebus(priv); - if (ret != OK) - { - fdbg("WARN: Failed to set wide bus operation: %d\n", ret); - } - - /* TODO: If widebus selected, then send CMD6 to see if the card supports - * high speed mode. A new SDIO method will be needed to set high speed - * mode. - */ - - return OK; -} - -/**************************************************************************** - * Name: mmcsd_cardidentify - * - * Description: - * We believe that there is media in the slot. Attempt to initialize and - * configure the card. This is called only from mmcsd_probe(). - * - ****************************************************************************/ - -static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) -{ - uint32_t response; - uint32_t start; - uint32_t elapsed; - uint32_t sdcapacity = MMCSD_ACMD41_STDCAPACITY; - int ret; - - /* Assume failure to identify the card */ - - priv->type = MMCSD_CARDTYPE_UNKNOWN; - - /* Check if there is a card present in the slot. This is normally a matter is - * of GPIO sensing. - */ - - if (!SDIO_PRESENT(priv->dev)) - { - fvdbg("No card present\n"); - return -ENODEV; - } - - /* Set ID mode clocking (<400KHz) */ - - SDIO_CLOCK(priv->dev, CLOCK_IDMODE); - - /* After power up at least 74 clock cycles are required prior to starting bus - * communication - */ - - up_udelay(MMCSD_POWERUP_DELAY); - - /* Then send CMD0 (twice just to be sure) */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD0, 0); - mmcsd_sendcmdpoll(priv, MMCSD_CMD0, 0); - up_udelay(MMCSD_IDLE_DELAY); - - /* Check for SDHC Version 2.x. Send CMD8 to verify SD card interface - * operating condition. CMD 8 is reserved on SD version 1.0 and MMC. - * - * CMD8 Argument: - * [31:12]: Reserved (shall be set to '0') - * [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V) - * [7:0]: Check Pattern (recommended 0xaa) - * CMD8 Response: R7 - */ - - ret = mmcsd_sendcmdpoll(priv, SD_CMD8, MMCSD_CMD8CHECKPATTERN|MMCSD_CMD8VOLTAGE_27); - if (ret == OK) - { - /* CMD8 was sent successfully... Get the R7 response */ - - ret = SDIO_RECVR7(priv->dev, SD_CMD8, &response); - } - - /* Were both the command sent and response received correctly? */ - - if (ret == OK) - { - /* CMD8 succeeded this is probably a SDHC card. Verify the operating - * voltage and that the check pattern was correctly echoed - */ - - if (((response & MMCSD_R7VOLTAGE_MASK) == MMCSD_R7VOLTAGE_27) && - ((response & MMCSD_R7ECHO_MASK) == MMCSD_R7CHECKPATTERN)) - { - fvdbg("SD V2.x card\n"); - priv->type = MMCSD_CARDTYPE_SDV2; - sdcapacity = MMCSD_ACMD41_HIGHCAPACITY; - } - else - { - fdbg("ERROR: R7: %08x\n", response); - return -EIO; - } - } - - /* At this point, type is either UNKNOWN or SDV2. Try sending - * CMD55 and (maybe) ACMD41 for up to 1 second or until the card - * exits the IDLE state. CMD55 is supported by SD V1.x and SD V2.x, - * but not MMC - */ - - start = clock_systimer(); - elapsed = 0; - do - { - /* We may have already determined that his card is an MMC card from - * an earlier pass through through this loop. In that case, we should - * skip the SD-specific commands. - */ - -#ifdef CONFIG_MMCSD_MMCSUPPORT - if (priv->type != MMCSD_CARDTYPE_MMC) -#endif - { - /* Send CMD55 with argument = 0 */ - - mmcsd_sendcmdpoll(priv, SD_CMD55, 0); - ret = mmcsd_recvR1(priv, SD_CMD55); - if (ret != OK) - { - /* I am a little confused.. I think both SD and MMC cards support - * CMD55 (but maybe only SD cards support CMD55). We'll make the - * the MMC vs. SD decision based on CMD1 and ACMD41. - */ - - fdbg("ERROR: mmcsd_recvR1(CMD55) failed: %d\n", ret); - } - else - { - /* Send ACMD41 */ - - mmcsd_sendcmdpoll(priv, SD_ACMD41, MMCSD_ACMD41_VOLTAGEWINDOW|sdcapacity); - ret = SDIO_RECVR3(priv->dev, SD_ACMD41, &response); - if (ret != OK) - { - /* If the error is a timeout, then it is probably an MMC card, - * but we will make the decision based on CMD1 below - */ - - fdbg("ERROR: ACMD41 RECVR3: %d\n", ret); - } - else - { - /* ACMD41 succeeded. ACMD41 is supported by SD V1.x and SD V2.x, - * but not MMC. If we did not previously determine that this is - * an SD V2.x (via CMD8), then this must be SD V1.x - */ - - fvdbg("R3: %08x\n", response); - if (priv->type == MMCSD_CARDTYPE_UNKNOWN) - { - fvdbg("SD V1.x card\n"); - priv->type = MMCSD_CARDTYPE_SDV1; - } - - /* Check if the card is busy. Very confusing, BUSY is set LOW - * if the card has not finished its initialization, so it really - * means NOT busy. - */ - - if ((response & MMCSD_CARD_BUSY) != 0) - { - /* No.. We really should check the current state to see if - * the SD card successfully made it to the IDLE state, but - * at least for now, we will simply assume that that is the - * case. - * - * Now, check if this is a SD V2.x card that supports block - * addressing - */ - - if ((response & MMCSD_R3_HIGHCAPACITY) != 0) - { - fvdbg("SD V2.x card with block addressing\n"); - DEBUGASSERT(priv->type == MMCSD_CARDTYPE_SDV2); - priv->type |= MMCSD_CARDTYPE_BLOCK; - } - - /* And break out of the loop with an SD card identified */ - - break; - } - } - } - } - - /* If we get here then either (1) CMD55 failed, (2) CMD41 failed, or (3) - * and SD or MMC card has been identified, but it is not yet in the IDLE state. - * If SD card has not been identified, then we might be looking at an - * MMC card. We can send the CMD1 to find out for sure. CMD1 is supported - * by MMC cards, but not by SD cards. - */ -#ifdef CONFIG_MMCSD_MMCSUPPORT - if (priv->type == MMCSD_CARDTYPE_UNKNOWN || priv->type == MMCSD_CARDTYPE_MMC) - { - /* Send the MMC CMD1 to specify the operating voltage. CMD1 causes - * transition to ready state/ card-identification mode. NOTE: If the - * card does not support this voltage range, it will go the inactive - * state. - * - * NOTE: An MMC card will only respond once to CMD1 (unless it is busy). - * This is part of the logic used to determine how many MMC cards are - * connected (This implementation supports only a single MMC card). So - * we cannot re-send CMD1 without first placing the card back into - * stand-by state (if the card is busy, it will automatically - * go back to the the standby state). - */ - - mmcsd_sendcmdpoll(priv, MMC_CMD1, MMCSD_VDD_33_34); - ret = SDIO_RECVR3(priv->dev, MMC_CMD1, &response); - - /* Was the operating range set successfully */ - - if (ret != OK) - { - fdbg("ERROR: CMD1 RECVR3: %d\n", ret); - } - else - { - /* CMD1 succeeded... this must be an MMC card */ - - fdbg("CMD1 succeeded, assuming MMC card\n"); - priv->type = MMCSD_CARDTYPE_MMC; - - /* Check if the card is busy. Very confusing, BUSY is set LOW - * if the card has not finished its initialization, so it really - * means NOT busy. - */ - - if ((response & MMCSD_CARD_BUSY) != 0) - { - /* NO.. We really should check the current state to see if the - * MMC successfully made it to the IDLE state, but at least for now, - * we will simply assume that that is the case. - * - * Then break out of the look with an MMC card identified - */ - - break; - } - } - } -#endif - /* Check the elapsed time. We won't keep trying this forever! */ - - elapsed = clock_systimer() - start; - } - while( elapsed < TICK_PER_SEC ); /* On successful reception while 'breaks', see above. */ - - /* We get here when the above loop completes, either (1) we could not - * communicate properly with the card due to errors (and the loop times - * out), or (3) it is an MMC or SD card that has successfully transitioned - * to the IDLE state (well, at least, it provided its OCR saying that it - * it is no longer busy). - */ - - if (elapsed >= TICK_PER_SEC || priv->type == MMCSD_CARDTYPE_UNKNOWN) - { - fdbg("ERROR: Failed to identify card\n"); - return -EIO; - } - - return OK; -} - -/**************************************************************************** - * Name: mmcsd_probe - * - * Description: - * Check for media inserted in a slot. Called (1) during initialization to - * see if there was a card in the slot at power up, (2) when/if a media - * insertion event occurs, or (3) if the BIOC_PROBE ioctl command is - * received. - * - ****************************************************************************/ - -static int mmcsd_probe(FAR struct mmcsd_state_s *priv) -{ - int ret; - - fvdbg("type: %d probed: %d\n", priv->type, priv->probed); - - /* If we have reliable card detection events and if we have - * already probed the card, then we don't need to do anything - * else - */ - -#ifdef CONFIG_MMCSD_HAVECARDDETECT - if (priv->probed && SDIO_PRESENT(priv->dev)) - { - return OK; - } -#endif - - /* Otherwise, we are going to probe the card. There are lots of - * possibilities here: We may think that there is a card in the slot, - * or not. There may be a card in the slot, or not. If there is - * card in the slot, perhaps it is a different card than we one we - * think is there? The safest thing to do is to process the card - * removal first and start from known place. - */ - - mmcsd_removed(priv); - - /* Now.. is there a card in the slot? */ - - if (SDIO_PRESENT(priv->dev)) - { - /* Yes.. probe it. First, what kind of card was inserted? */ - - ret = mmcsd_cardidentify(priv); - if (ret != OK) - { - fdbg("ERROR: Failed to initialize card: %d\n", ret); -#ifdef CONFIG_MMCSD_HAVECARDDETECT - SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); -#endif - } - else - { - /* Then initialize the driver according to the identified card type */ - - switch (priv->type) - { - case MMCSD_CARDTYPE_SDV1: /* Bit 1: SD version 1.x */ - case MMCSD_CARDTYPE_SDV2: /* SD version 2.x with byte addressing */ - case MMCSD_CARDTYPE_SDV2|MMCSD_CARDTYPE_BLOCK: /* SD version 2.x with block addressing */ - ret = mmcsd_sdinitialize(priv); - break; - - case MMCSD_CARDTYPE_MMC: /* MMC card */ -#ifdef CONFIG_MMCSD_MMCSUPPORT - ret = mmcsd_mmcinitialize(priv); - break; -#endif - case MMCSD_CARDTYPE_UNKNOWN: /* Unknown card type */ - default: - fdbg("ERROR: Internal confusion: %d\n", priv->type); - ret = -EPERM; - break; - }; - - /* Was the card configured successfully? */ - - if (ret == OK) - { - /* Yes... */ - - fvdbg("Capacity: %lu Kbytes\n", (unsigned long)(priv->capacity / 1024)); - priv->mediachanged = true; - - /* Set up to receive asynchronous, media removal events */ - - SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_EJECTED); - } - } - - /* In any event, we have probed this card */ - - priv->probed = true; - } - else - { - /* There is no card in the slot */ - - fvdbg("No card\n"); -#ifdef CONFIG_MMCSD_HAVECARDDETECT - SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); -#endif - ret = -ENODEV; - } - - return ret; -} - -/**************************************************************************** - * Name: mmcsd_removed - * - * Description: - * Disable support for media in the slot. Called (1) when/if a media - * removal event occurs, or (2) if the BIOC_EJECT ioctl command is - * received. - * - ****************************************************************************/ - -static int mmcsd_removed(FAR struct mmcsd_state_s *priv) -{ - fvdbg("type: %d present: %d\n", priv->type, SDIO_PRESENT(priv->dev)); - - /* Forget the card geometry, pretend the slot is empty (it might not - * be), and that the card has never been initialized. - */ - - priv->capacity = 0; /* Capacity=0 sometimes means no media */ - priv->blocksize = 0; - priv->mediachanged = false; - priv->type = MMCSD_CARDTYPE_UNKNOWN; - priv->probed = false; - priv->rca = 0; - priv->selblocklen = 0; - - /* Go back to the default 1-bit data bus. */ - - SDIO_WIDEBUS(priv->dev, false); - priv->widebus = false; - - /* Disable clocking to the card */ - - (void)SDIO_CLOCK(priv->dev, CLOCK_SDIO_DISABLED); - return OK; -} - -/**************************************************************************** - * Name: mmcsd_hwinitialize - * - * Description: - * One-time hardware initialization. Called only from sdio_slotinitialize. - * - ****************************************************************************/ - -static int mmcsd_hwinitialize(FAR struct mmcsd_state_s *priv) -{ - int ret; - - mmcsd_takesem(priv); - -#ifdef CONFIG_SDIO_DMA - /* Does this architecture support DMA with the MMC/SD device? */ - - priv->dma = SDIO_DMASUPPORTED(priv->dev); - fvdbg("DMA supported: %d\n", priv->dma); -#endif - - /* Attach and prepare MMC/SD interrupts */ - - if (SDIO_ATTACH(priv->dev)) - { - fdbg("ERROR: Unable to attach MMC/SD interrupts\n"); - mmcsd_givesem(priv); - return -EBUSY; - } - fvdbg("Attached MMC/SD interrupts\n"); - - /* Register a callback so that we get informed if media is inserted or - * removed from the slot (Initially all callbacks are disabled). - */ - - SDIO_REGISTERCALLBACK(priv->dev, mmcsd_mediachange, (FAR void *)priv); - - /* Is there a card in the slot now? For an MMC/SD card, there are three - * possible card detect mechanisms: - * - * 1. Mechanical insertion that can be detected using the WP switch - * that is closed when a card is inserted into then SD slot (SD - * "hot insertion capable" card conector only) - * 2. Electrical insertion that can be sensed using the pull-up resistor - * on CD/DAT3 (both SD/MMC), - * 3. Or by periodic attempts to initialize the card from software. - * - * The behavior of SDIO_PRESENT() is to use whatever information is available - * on the particular platform. If no card insertion information is available - * (polling only), then SDIO_PRESENT() will always return true and we will - * try to initialize the card. - */ - - if (SDIO_PRESENT(priv->dev)) - { - /* Yes... probe for a card in the slot */ - - ret = mmcsd_probe(priv); - if (ret != OK) - { - fvdbg("Slot not empty, but initialization failed: %d\n", ret); - - /* NOTE: The failure to initialize a card does not mean that - * initialization has failed! A card could be installed in the slot - * at a later time. ENODEV is return in this case, - * sdio_slotinitialize will use this return value to set up the - * card inserted callback event. - */ - - ret = -ENODEV; - } - } - else - { - /* ENODEV is returned to indicate that no card is inserted in the slot. - * sdio_slotinitialize will use this return value to set up the card - * inserted callback event. - */ - - ret = -ENODEV; - } - - /* OK is returned only if the slot initialized correctly AND the card in - * the slot was successfully configured. - */ - - mmcsd_givesem(priv); - return ret; -} - -/**************************************************************************** - * Name: mmcsd_hwuninitialize - * - * Description: - * Restore the MMC/SD slot to the uninitialized state. Called only from - * sdio_slotinitialize on a failure to initialize. - * - ****************************************************************************/ - -static void mmcsd_hwuninitialize(FAR struct mmcsd_state_s *priv) -{ - if (priv) - { - mmcsd_removed(priv); - SDIO_RESET(priv->dev); - kfree(priv); - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_slotinitialize - * - * Description: - * Initialize one slot for operation using the MMC/SD interface - * - * Input Parameters: - * minor - The MMC/SD minor device number. The MMC/SD device will be - * registered as /dev/mmcsdN where N is the minor number - * dev - And instance of an MMC/SD interface. The MMC/SD hardware should - * be initialized and ready to use. - * - ****************************************************************************/ - -int mmcsd_slotinitialize(int minor, FAR struct sdio_dev_s *dev) -{ - FAR struct mmcsd_state_s *priv; - char devname[16]; - int ret = -ENOMEM; - - fvdbg("minor: %d\n", minor); - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (minor < 0 || minor > 255 || !dev) - { - return -EINVAL; - } -#endif - - /* Allocate a MMC/SD state structure */ - - priv = (FAR struct mmcsd_state_s *)kmalloc(sizeof(struct mmcsd_state_s)); - if (priv) - { - /* Initialize the MMC/SD state structure */ - - memset(priv, 0, sizeof(struct mmcsd_state_s)); - sem_init(&priv->sem, 0, 1); - - /* Bind the MMCSD driver to the MMCSD state structure */ - - priv->dev = dev; - - /* Initialize the hardware associated with the slot */ - - ret = mmcsd_hwinitialize(priv); - - /* Was the slot initialized successfully? */ - - if (ret != OK) - { - /* No... But the error ENODEV is returned if hardware initialization - * succeeded but no card is inserted in the slot. In this case, the - * no error occurred, but the driver is still not ready. - */ - - if (ret == -ENODEV) - { - /* No card in the slot (or if there is, we could not recognize - * it).. Setup to receive the media inserted event - */ - - SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); - - fdbg("MMC/SD slot is empty\n"); - } - else - { - /* Some other non-recoverable bad thing happened */ - - fdbg("ERROR: Failed to initialize MMC/SD slot: %d\n", ret); - goto errout_with_alloc; - } - } - - /* Initialize buffering */ - -#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) - - ret = rwb_initialize(&priv->rwbuffer); - if (ret < 0) - { - fdbg("ERROR: Buffer setup failed: %d\n", ret); - goto errout_with_hwinit; - } -#endif - - /* Create a MMCSD device name */ - - snprintf(devname, 16, "/dev/mmcsd%d", minor); - - /* Inode private data is a reference to the MMCSD state structure */ - - ret = register_blockdriver(devname, &g_bops, 0, priv); - if (ret < 0) - { - fdbg("ERROR: register_blockdriver failed: %d\n", ret); - goto errout_with_buffers; - } - } - return OK; - -errout_with_buffers: -#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) - rwb_uninitialize(&priv->rwbuffer); -errout_with_hwinit: -#endif - mmcsd_hwuninitialize(priv); /* This will free the private data structure */ - return ret; - -errout_with_alloc: - kfree(priv); - return ret; -} - -#endif /* defined (CONFIG_MMCSD) && defined (CONFIG_MMCSD_SDIO) */ diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.h b/nuttx/drivers/mmcsd/mmcsd_sdio.h deleted file mode 100644 index 9e3794e25..000000000 --- a/nuttx/drivers/mmcsd/mmcsd_sdio.h +++ /dev/null @@ -1,339 +0,0 @@ -/******************************************************************************************** - * drivers/mmcsd/mmcsd_sdio.h - * - * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ********************************************************************************************/ - -#ifndef __DRIVERS_MMCSD_MMCSD_SDIO_H -#define __DRIVERS_MMCSD_MMCSD_SDIO_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -#include -#include - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ - -/* CMD8 Argument: - * [31:12]: Reserved (shall be set to '0') - * [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V) - * [7:0]: Check Pattern (recommended 0xaa) - * CMD8 Response: R7 - */ - -#define MMCSD_CMD8VOLTAGE_SHIFT (8) /* Bits 8-11: Supply voltage */ -#define MMCSD_CMD8VOLTAGE_MASK ((uint32_t)0x0f << MMCSD_CMD8VOLTAGE_SHIFT) -# define MMCSD_CMD8VOLTAGE_27 ((uint32_t)0x01 << MMCSD_CMD8VOLTAGE_SHIFT) /* 2.7-3.6V */ -#define MMCSD_CMD8ECHO_SHIFT (0) /* Bits 0-7: Check pattern */ -#define MMCSD_CMD8ECHO_MASK ((uint32_t)0xff << MMCSD_CMD8ECHO_SHIFT) -# define MMCSD_CMD8CHECKPATTERN ((uint32_t)0xaa << MMCSD_CMD8ECHO_SHIFT) - -/* ACMD6 argument */ - -#define MMCSD_ACMD6_BUSWIDTH_1 ((uint32_t)0) /* Bus width = 1-bit */ -#define MMCSD_ACMD6_BUSWIDTH_4 ((uint32_t)2) /* Bus width = 4-bit */ - -/* ACMD41 argument */ - -#define MMCSD_ACMD41_VOLTAGEWINDOW ((uint32_t)0x80100000) -#define MMCSD_ACMD41_HIGHCAPACITY ((uint32_t)1 << 30) -#define MMCSD_ACMD41_STDCAPACITY ((uint32_t)0) - -/* ACMD42 argument */ - -#define MMCSD_ACMD42_CD_DISCONNECT ((uint32_t)0) /* Disconnect card detection logic */ -#define MMCSD_ACMD42_CD_CONNECT ((uint32_t)1) /* Connect card detection logic */ - -/* R1 Card Status bit definitions */ - -#define MMCSD_R1_OUTOFRANGE ((uint32_t)1 << 31) /* Bad argument */ -#define MMCSD_R1_ADDRESSERROR ((uint32_t)1 << 30) /* Bad address */ -#define MMCSD_R1_BLOCKLENERROR ((uint32_t)1 << 29) /* Bad block length */ -#define MMCSD_R1_ERASESEQERROR ((uint32_t)1 << 28) /* Erase cmd error */ -#define MMCSD_R1_ERASEPARAM ((uint32_t)1 << 27) /* Bad write blocks */ -#define MMCSD_R1_WPVIOLATION ((uint32_t)1 << 26) /* Erase access failure */ -#define MMCSD_R1_CARDISLOCKED ((uint32_t)1 << 25) /* Card is locked */ -#define MMCSD_R1_LOCKUNLOCKFAILED ((uint32_t)1 << 24) /* Password error */ -#define MMCSD_R1_COMCRCERROR ((uint32_t)1 << 23) /* CRC error */ -#define MMCSD_R1_ILLEGALCOMMAND ((uint32_t)1 << 22) /* Bad command */ -#define MMCSD_R1_CARDECCFAILED ((uint32_t)1 << 21) /* Failed to correct data */ -#define MMCSD_R1_CCERROR ((uint32_t)1 << 20) /* Card controller error */ -#define MMCSD_R1_ERROR ((uint32_t)1 << 19) /* General error */ -#define MMCSD_R1_UNDERRUN ((uint32_t)1 << 18) /* Underrun (MMC only) */ -#define MMCSD_R1_OVERRRUN ((uint32_t)1 << 17) /* Overrun (MMC only) */ -#define MMCSD_R1_CIDCSDOVERWRITE ((uint32_t)1 << 16) /* CID/CSD error */ -#define MMCSD_R1_WPERASESKIP ((uint32_t)1 << 15) /* Not all erased */ -#define MMCSD_R1_CARDECCDISABLED ((uint32_t)1 << 14) /* Internal ECC not used */ -#define MMCSD_R1_ERASERESET ((uint32_t)1 << 13) /* Reset sequence cleared */ -#define MMCSD_R1_STATE_SHIFT (9) /* Current card state */ -#define MMCSD_R1_STATE_MASK ((uint32_t)15 << MMCSD_R1_STATE_SHIFT) - /* Card identification mode states */ -# define MMCSD_R1_STATE_IDLE ((uint32_t)0 << MMCSD_R1_STATE_SHIFT) /* 0=Idle state */ -# define MMCSD_R1_STATE_READY ((uint32_t)1 << MMCSD_R1_STATE_SHIFT) /* 1=Ready state */ -# define MMCSD_R1_STATE_IDENT ((uint32_t)2 << MMCSD_R1_STATE_SHIFT) /* 2=Identification state */ - /* Data transfer states */ -# define MMCSD_R1_STATE_STBY ((uint32_t)3 << MMCSD_R1_STATE_SHIFT) /* 3=Standby state */ -# define MMCSD_R1_STATE_TRAN ((uint32_t)4 << MMCSD_R1_STATE_SHIFT) /* 4=Transfer state */ -# define MMCSD_R1_STATE_DATA ((uint32_t)5 << MMCSD_R1_STATE_SHIFT) /* 5=Sending data state */ -# define MMCSD_R1_STATE_RCV ((uint32_t)6 << MMCSD_R1_STATE_SHIFT) /* 6=Receiving data state */ -# define MMCSD_R1_STATE_PRG ((uint32_t)7 << MMCSD_R1_STATE_SHIFT) /* 7=Programming state */ -# define MMCSD_R1_STATE_DIS ((uint32_t)8 << MMCSD_R1_STATE_SHIFT) /* 8=Disconnect state */ -#define MMCSD_R1_READYFORDATA ((uint32_t)1 << 8) /* Buffer empty */ -#define MMCSD_R1_APPCMD ((uint32_t)1 << 5) /* Next CMD is ACMD */ -#define MMCSD_R1_AKESEQERROR ((uint32_t)1 << 3) /* Authentication error */ -#define MMCSD_R1_ERRORMASK ((uint32_t)0xfdffe008) /* Error mask */ - -#define IS_STATE(v,s) ((((uint32_t)v)&MMCSD_R1_STATE_MASK)==(s)) - -/* R3 (OCR) */ - -#define MMC_VDD_20_36 ((uint32_t)0x00ffff00) /* VDD voltage 2.0-3.6 */ - -#define MMCSD_VDD_145_150 ((uint32_t)1 << 0) /* VDD voltage 1.45 - 1.50 */ -#define MMCSD_VDD_150_155 ((uint32_t)1 << 1) /* VDD voltage 1.50 - 1.55 */ -#define MMCSD_VDD_155_160 ((uint32_t)1 << 2) /* VDD voltage 1.55 - 1.60 */ -#define MMCSD_VDD_160_165 ((uint32_t)1 << 3) /* VDD voltage 1.60 - 1.65 */ -#define MMCSD_VDD_165_170 ((uint32_t)1 << 4) /* VDD voltage 1.65 - 1.70 */ -#define MMCSD_VDD_17_18 ((uint32_t)1 << 5) /* VDD voltage 1.7 - 1.8 */ -#define MMCSD_VDD_18_19 ((uint32_t)1 << 6) /* VDD voltage 1.8 - 1.9 */ -#define MMCSD_VDD_19_20 ((uint32_t)1 << 7) /* VDD voltage 1.9 - 2.0 */ -#define MMCSD_VDD_20_21 ((uint32_t)1 << 8) /* VDD voltage 2.0-2.1 */ -#define MMCSD_VDD_21_22 ((uint32_t)1 << 9) /* VDD voltage 2.1-2.2 */ -#define MMCSD_VDD_22_23 ((uint32_t)1 << 10) /* VDD voltage 2.2-2.3 */ -#define MMCSD_VDD_23_24 ((uint32_t)1 << 11) /* VDD voltage 2.3-2.4 */ -#define MMCSD_VDD_24_25 ((uint32_t)1 << 12) /* VDD voltage 2.4-2.5 */ -#define MMCSD_VDD_25_26 ((uint32_t)1 << 13) /* VDD voltage 2.5-2.6 */ -#define MMCSD_VDD_26_27 ((uint32_t)1 << 14) /* VDD voltage 2.6-2.7 */ -#define MMCSD_VDD_27_28 ((uint32_t)1 << 15) /* VDD voltage 2.7-2.8 */ -#define MMCSD_VDD_28_29 ((uint32_t)1 << 16) /* VDD voltage 2.8-2.9 */ -#define MMCSD_VDD_29_30 ((uint32_t)1 << 17) /* VDD voltage 2.9-3.0 */ -#define MMCSD_VDD_30_31 ((uint32_t)1 << 18) /* VDD voltage 3.0-3.1 */ -#define MMCSD_VDD_31_32 ((uint32_t)1 << 19) /* VDD voltage 3.1-3.2 */ -#define MMCSD_VDD_32_33 ((uint32_t)1 << 20) /* VDD voltage 3.2-3.3 */ -#define MMCSD_VDD_33_34 ((uint32_t)1 << 21) /* VDD voltage 3.3-3.4 */ -#define MMCSD_VDD_34_35 ((uint32_t)1 << 22) /* VDD voltage 3.4-3.5 */ -#define MMCSD_VDD_35_36 ((uint32_t)1 << 23) /* VDD voltage 3.5-3.6 */ -#define MMCSD_R3_HIGHCAPACITY ((uint32_t)1 << 30) /* true: Card supports block addressing */ -#define MMCSD_CARD_BUSY ((uint32_t)1 << 31) /* Card power-up busy bit */ - -/* R6 Card Status bit definitions */ - -#define MMCSD_R6_RCA_SHIFT (16) /* New published RCA */ -#define MMCSD_R6_RCA_MASK ((uint32_t)0xffff << MMCSD_R6_RCA_SHIFT) -#define MMCSD_R6_COMCRCERROR ((uint32_t)1 << 15) /* CRC error */ -#define MMCSD_R6_ILLEGALCOMMAND ((uint32_t)1 << 14) /* Bad command */ -#define MMCSD_R6_ERROR ((uint32_t)1 << 13) /* General error */ -#define MMCSD_R6_STATE_SHIFT (9) /* Current card state */ -#define MMCSD_R6_STATE_MASK ((uint32_t)15 << MMCSD_R6_STATE_SHIFT) - /* Card identification mode states */ -# define MMCSD_R6_STATE_IDLE ((uint32_t)0 << MMCSD_R6_STATE_SHIFT) /* 0=Idle state */ -# define MMCSD_R6_STATE_READY ((uint32_t)1 << MMCSD_R6_STATE_SHIFT) /* 1=Ready state */ -# define MMCSD_R6_STATE_IDENT ((uint32_t)2 << MMCSD_R6_STATE_SHIFT) /* 2=Identification state */ - /* Data transfer states */ -# define MMCSD_R6_STATE_STBY ((uint32_t)3 << MMCSD_R6_STATE_SHIFT) /* 3=Standby state */ -# define MMCSD_R6_STATE_TRAN ((uint32_t)4 << MMCSD_R6_STATE_SHIFT) /* 4=Transfer state */ -# define MMCSD_R6_STATE_DATA (5(uint32_t) << MMCSD_R6_STATE_SHIFT) /* 5=Sending data state */ -# define MMCSD_R6_STATE_RCV ((uint32_t)6 << MMCSD_R6_STATE_SHIFT) /* 6=Receiving data state */ -# define MMCSD_R6_STATE_PRG ((uint32_t)7 << MMCSD_R6_STATE_SHIFT) /* 7=Programming state */ -# define MMCSD_R6_STATE_DIS ((uint32_t) << MMCSD_R6_STATE_SHIFT) /* 8=Disconnect state */ -#define MMCSD_R6_ERRORMASK ((uint32_t)0x0000e000) /* Error mask */ - -/* SD Configuration Register (SCR) encoding */ - -#define MMCSD_SCR_BUSWIDTH_1BIT (1) -#define MMCSD_SCR_BUSWIDTH_2BIT (2) -#define MMCSD_SCR_BUSWIDTH_4BIT (4) -#define MMCSD_SCR_BUSWIDTH_8BIT (8) - -/* Last 4 bytes of the 48-bit R7 response */ - -#define MMCSD_R7VERSION_SHIFT (28) /* Bits 28-31: Command version number */ -#define MMCSD_R7VERSION_MASK ((uint32_t)0x0f << MMCSD_R7VERSION_SHIFT) -#define MMCSD_R7VOLTAGE_SHIFT (8) /* Bits 8-11: Voltage accepted */ -#define MMCSD_R7VOLTAGE_MASK ((uint32_t)0x0f << MMCSD_R7VOLTAGE_SHIFT) -# define MMCSD_R7VOLTAGE_27 ((uint32_t)0x01 << MMCSD_R7VOLTAGE_SHIFT) /* 2.7-3.6V */ -#define MMCSD_R7ECHO_SHIFT (0) /* Bits 0-7: Echoed check pattern */ -#define MMCSD_R7ECHO_MASK ((uint32_t)0xff << MMCSD_R7ECHO_SHIFT) -# define MMCSD_R7CHECKPATTERN ((uint32_t)0xaa << MMCSD_R7ECHO_SHIFT) - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ - -/* Decoded Card Identification (CID) register */ - -struct mmcsd_cid_s -{ - uint8_t mid; /* 127:120 8-bit Manufacturer ID */ - uint16_t oid; /* 119:104 16-bit OEM/Application ID (ascii) */ - uint8_t pnm[6]; /* 103:64 40-bit Product Name (ascii) + null terminator */ - uint8_t prv; /* 63:56 8-bit Product revision */ - uint32_t psn; /* 55:24 32-bit Product serial number */ - /* 23:20 4-bit (reserved) */ - uint16_t mdt; /* 19:8 12-bit Manufacturing date */ - uint8_t crc; /* 7:1 7-bit CRC7 */ - /* 0:0 1-bit (not used) */ -}; - -/* Decoded Card Specific Data (CSD) register */ - -struct mmcsd_csd_s -{ - uint8_t csdstructure; /* 127:126 CSD structure */ - uint8_t mmcspecvers; /* 125:122 MMC Spec version (MMC only) */ - - struct - { - uint8_t timeunit; /* 2:0 Time exponent */ - uint8_t timevalue; /* 6:3 Time mantissa */ - } taac; /* 119:112 Data read access-time-1 */ - - uint8_t nsac; /* 111:104 Data read access-time-2 in CLK cycle(NSAC*100) */ - - struct - { - uint8_t transferrateunit; /* 2:0 Rate exponent */ - uint8_t timevalue; /* 6:3 Rate mantissa */ - } transpeed; /* 103:96 Max. data transfer rate */ - - uint16_t ccc; /* 95:84 Card command classes */ - uint8_t readbllen; /* 83:80 Max. read data block length */ - uint8_t readblpartial; /* 79:79 Partial blocks for read allowed */ - uint8_t writeblkmisalign; /* 78:78 Write block misalignment */ - uint8_t readblkmisalign; /* 77:77 Read block misalignment */ - uint8_t dsrimp; /* 76:76 DSR implemented */ - - union - { -#ifdef CONFIG_MMCSD_MMCSUPPORT - struct - { - uint16_t csize; /* 73:62 Device size */ - uint8_t vddrcurrmin; /* 61:59 Max. read current at Vdd min */ - uint8_t vddrcurrmax; /* 58:56 Max. read current at Vdd max */ - uint8_t vddwcurrmin; /* 55:53 Max. write current at Vdd min */ - uint8_t vddwcurrmax; /* 52:50 Max. write current at Vdd max */ - uint8_t csizemult; /* 49:47 Device size multiplier */ - - union - { - struct /* MMC system specification version 3.1 */ - { - uint8_t ergrpsize; /* 46:42 Erase group size (MMC 3.1) */ - uint8_t ergrpmult; /* 41:37 Erase group multiplier (MMC 3.1) */ - } mmc31; - struct /* MMC system specification version 2.2 */ - { - uint8_t sectorsize; /* 46:42 Erase sector size (MMC 2.2) */ - uint8_t ergrpsize; /* 41:37 Erase group size (MMC 2.2) */ - } mmc22; - } er; - - uint8_t mmcwpgrpsize; /* 36:32 Write protect group size (MMC) */ - } mmc; -#endif - struct - { - uint16_t csize; /* 73:62 Device size */ - uint8_t vddrcurrmin; /* 61:59 Max. read current at Vdd min */ - uint8_t vddrcurrmax; /* 58:56 Max. read current at Vdd max */ - uint8_t vddwcurrmin; /* 55:53 Max. write current at Vdd min */ - uint8_t vddwcurrmax; /* 52:50 Max. write current at Vdd max */ - uint8_t csizemult; /* 49:47 Device size multiplier */ - uint8_t sderblen; /* 46:46 Erase single block enable (SD) */ - uint8_t sdsectorsize; /* 45:39 Erase sector size (SD) */ - uint8_t sdwpgrpsize; /* 38:32 Write protect group size (SD) */ - } sdbyte; - - struct - { - /* 73:70 (reserved) */ - uint32_t csize; /* 69:48 Device size */ - /* 47:47 (reserved) */ - uint8_t sderblen; /* 46:46 Erase single block enable (SD) */ - uint8_t sdsectorsize; /* 45:39 Erase sector size (SD) */ - uint8_t sdwpgrpsize; /* 38:32 Write protect group size (SD) */ - } sdblock; - } u; - - uint8_t wpgrpen; /* 31:31 Write protect group enable */ - uint8_t mmcdfltecc; /* 30:29 Manufacturer default ECC (MMC) */ - uint8_t r2wfactor; /* 28:26 Write speed factor */ - uint8_t writebllen; /* 25:22 Max. write data block length */ - uint8_t writeblpartial; /* 21:21 Partial blocks for write allowed */ - uint8_t fileformatgrp; /* 15:15 File format group */ - uint8_t copy; /* 14:14 Copy flag (OTP) */ - uint8_t permwriteprotect; /* 13:13 Permanent write protection */ - uint8_t tmpwriteprotect; /* 12:12 Temporary write protection */ - uint8_t fileformat; /* 10:11 File format */ - uint8_t mmcecc; /* 9:8 ECC (MMC) */ - uint8_t crc; /* 7:1 CRC */ - /* 0:0 Not used */ -}; - -struct mmcsd_scr_s -{ - uint8_t scrversion; /* 63:60 Version of SCR structure */ - uint8_t sdversion; /* 59:56 SD memory card physical layer version */ - uint8_t erasestate; /* 55:55 Data state after erase (1 or 0) */ - uint8_t security; /* 54:52 SD security support */ - uint8_t buswidth; /* 51:48 DAT bus widthes supported */ - /* 47:32 SD reserved space */ - uint32_t mfgdata; /* 31:0 Reserved for manufacturing data */ -}; - -/******************************************************************************************** - * Public Data - ********************************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -/******************************************************************************************** - * Public Functions - ********************************************************************************************/ - - -#undef EXTERN -#if defined(__cplusplus) -} -#endif -#endif /* __DRIVERS_MMCSD_MMCSD_SDIO_H */ diff --git a/nuttx/drivers/mmcsd/mmcsd_spi.c b/nuttx/drivers/mmcsd/mmcsd_spi.c deleted file mode 100644 index 3d4cf1dd1..000000000 --- a/nuttx/drivers/mmcsd/mmcsd_spi.c +++ /dev/null @@ -1,1889 +0,0 @@ -/**************************************************************************** - * drivers/mmcsd/mmcsd_spi.c - * - * Copyright (C) 2008-2010, 2011-2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#if defined (CONFIG_MMCSD) && defined (CONFIG_MMCSD_SPI) - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "mmcsd_spi.h" -#include "mmcsd_csd.h" -#include "mmcsd_internal.h" - -/**************************************************************************** - * Pre-Processor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -#ifndef CONFIG_MMCSD_NSLOTS -# ifdef CONFIG_CPP_HAVE_WARNING -# warning "CONFIG_MMCSD_NSLOTS not defined" -# endif -# define CONFIG_MMCSD_NSLOTS 1 -#endif - -#define MMCSD_IDMODE_CLOCK (400000) - -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_READONLY) -# define MMCSD_MODE 0666 -#else -# define MMCSD_MODE 0444 -#endif - -#ifndef CONFIG_MMCSD_SPICLOCK -# define CONFIG_MMCSD_SPICLOCK 20000000 -#endif - -#ifndef CONFIG_MMCSD_SECTOR512 -# define CONFIG_MMCSD_SECTOR512 /* Force 512 byte sectors on all cards */ -#endif - -/* Slot struct info *********************************************************/ -/* Slot status definitions */ - -#define MMCSD_SLOTSTATUS_NOTREADY 0x01 /* Card not initialized */ -#define MMCSD_SLOTSTATUS_NODISK 0x02 /* No card in the slot */ -#define MMCSD_SLOTSTATUS_WRPROTECT 0x04 /* Card is write protected */ -#define MMCSD_SLOTSTATUS_MEDIACHGD 0x08 /* Media changed in slot */ - -/* Values in the MMC/SD command table ***************************************/ -/* These define the value returned by the MMC/SD command */ - -#define MMCSD_CMDRESP_R1 0 -#define MMCSD_CMDRESP_R1B 1 -#define MMCSD_CMDRESP_R2 2 -#define MMCSD_CMDRESP_R3 3 -#define MMCSD_CMDRESP_R7 4 - -#ifdef CONFIG_MMCSD_SECTOR512 -# define SECTORSIZE(s) (512) -#else -# define SECTORSIZE(s) ((s)->sectorsize) -#endif - -/* Time delays in units of the system clock. CLK_TCK is the number of clock - * ticks per second. - */ - -#define MMCSD_DELAY_10MS (CLK_TCK/100 + 1) -#define MMCSD_DELAY_50MS (CLK_TCK/20 + 1) -#define MMCSD_DELAY_100MS (CLK_TCK/10 + 1) -#define MMCSD_DELAY_250MS (CLK_TCK/4 + 1) -#define MMCSD_DELAY_500MS (CLK_TCK/2 + 1) -#define MMCSD_DELAY_1SEC (CLK_TCK + 1) -#define MMCSD_DELAY_10SEC (10 * CLK_TCK + 1) - -#define ELAPSED_TIME(t) (clock_systimer()-(t)) -#define START_TIME (clock_systimer()) - -/* SD read timeout: ~100msec, Write Time out ~250ms. Units of clock ticks */ - -#define SD_READACCESS MMCSD_DELAY_100MS -#define SD_WRITEACCESS MMCSD_DELAY_250MS - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure represents the state of one card slot */ - -struct mmcsd_slot_s -{ - FAR struct spi_dev_s *spi; /* SPI port bound to this slot */ - sem_t sem; /* Assures mutually exclusive accesss to card and SPI */ - uint8_t state; /* State of the slot (see MMCSD_SLOTSTATUS_* definitions) */ - uint8_t type; /* Disk type */ - uint8_t csd[16]; /* Copy of card CSD */ -#ifndef CONFIG_MMCSD_SECTOR512 - uint16_t sectorsize; /* Media block size (in bytes) */ -#endif - uint32_t nsectors; /* Number of blocks on the media */ - uint32_t taccess; /* Card access time */ - uint32_t twrite; /* Card write time */ - uint32_t ocr; /* Last 4 bytes of OCR (R3) */ - uint32_t r7; /* Last 4 bytes of R7 */ -}; - -struct mmcsd_cmdinfo_s -{ - uint8_t cmd; - uint8_t resp; - uint8_t chksum; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Misc *********************************************************************/ - -static void mmcsd_semtake(sem_t *sem); - -/* Card SPI interface *******************************************************/ - -static int mmcsd_waitready(FAR struct mmcsd_slot_s *slot); -static uint32_t mmcsd_sendcmd(FAR struct mmcsd_slot_s *slot, - const struct mmcsd_cmdinfo_s *cmd, uint32_t arg); -static void mmcsd_setblklen(FAR struct mmcsd_slot_s *slot, - uint32_t length); -static uint32_t mmcsd_nsac(FAR struct mmcsd_slot_s *slot, uint8_t *csd, - uint32_t frequency); -static uint32_t mmcsd_taac(FAR struct mmcsd_slot_s *slot, uint8_t *csd); -static void mmcsd_decodecsd(FAR struct mmcsd_slot_s *slot, uint8_t *csd); -static void mmcsd_checkwrprotect(FAR struct mmcsd_slot_s *slot, - uint8_t *csd); -static int mmcsd_getcardinfo(FAR struct mmcsd_slot_s *slot, - uint8_t *buffer, const struct mmcsd_cmdinfo_s *cmd); - -#define mmcsd_getcsd(slot, csd) mmcsd_getcardinfo(slot, csd, &g_cmd9); -#define mmcsd_getcid(slot, cid) mmcsd_getcardinfo(slot, cid, &g_cmd10); - -static int mmcsd_recvblock(FAR struct mmcsd_slot_s *slot, - uint8_t *buffer, int nbytes); -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_READONLY) -static int mmcsd_xmitblock(FAR struct mmcsd_slot_s *slot, - const uint8_t *buffer, int nbytes, uint8_t token); -#endif - -/* Block driver interfaces **************************************************/ - -static int mmcsd_open(FAR struct inode *inode); -static int mmcsd_close(FAR struct inode *inode); -static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors); -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_READONLY) -static ssize_t mmcsd_write(FAR struct inode *inode, - const unsigned char *buffer, size_t start_sector, - unsigned int nsectors); -#endif -static int mmcsd_geometry(FAR struct inode *inode, - struct geometry *geometry); - -/* Initialization ***********************************************************/ - -static int mmcsd_mediainitialize(FAR struct mmcsd_slot_s *slot); -static void mmcsd_mediachanged(void *arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* Driver state *************************************************************/ - -/* These are the lock driver methods supported by this file */ - -static const struct block_operations g_bops = -{ - mmcsd_open, /* open */ - mmcsd_close, /* close */ - mmcsd_read, /* read */ -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_READONLY) - mmcsd_write, /* write */ -#else - NULL, /* write */ -#endif - mmcsd_geometry, /* geometry */ - NULL /* ioctl */ -}; - -/* A slot structure allocated for each configured slot */ - -static struct mmcsd_slot_s g_mmcsdslot[CONFIG_MMCSD_NSLOTS]; - -/* Timing *******************************************************************/ - -/* We will use the TRAN_SPEED from the CSD to determine the maximum SPI - * clocking (TRAN_SPEED defines the maximum transfer rate per bit per data - * line). - * - * The CSD TRAN_SPEED is provided as a 3 bit rate unit (RU) and a 4 bit time - * value (TU). We need the transfer frequency which is: RU*TU bits/sec - * - * g_transpeedru holds RU/10 and g_transpeedtu holds TU*10 so that the - * correct value is returned in the product - */ - -static const uint32_t g_transpeedru[8] = -{ - 10000, /* 0: 10 Kbit/sec / 10 */ - 100000, /* 1: 1 Mbit/sec / 10 */ - 1000000, /* 2: 10 Mbit/sec / 10 */ - 10000000, /* 3: 100 Mbit/sec / 10*/ - - 0, 0, 0, 0 /* 4-7: Reserved values */ -}; - -static const uint32_t g_transpeedtu[16] = -{ - 0, 10, 12, 13, /* 0-3: Reserved, 1.0, 1.1, 1.2, 1.3 */ - 15, 20, 25, 30, /* 4-7: 1.5, 2.0, 2.5, 3.0 */ - 35, 40, 45, 50, /* 8-11: 3.5, 4.0, 4.5, 5.0 */ - 55, 60, 70, 80, /* 12-15: 5.5, 6.0, 7.0, 8.0 */ -}; - -/* The TAAC defines the asynchronous part of the data access time. The - * read access time the sum of the TAAC and the NSAC. These define the - * time from the end bit of the read command to start bit of the data block. - * - * The TAAC consists of a 3-bit time unit (TU) and a 4-bit time value (TV). - * TAAC is in units of time; NSAC is in units of SPI clocks. - * The access time we need is then given by: - * - * taccess = TU*TV + NSAC/spifrequency - * - * g_taactu holds TU in units of nanoseconds and microseconds (you have to use - * the index to distiguish). g_taactv holds TV with 8-bits of fraction. - */ - -#define MAX_USTUNDX 2 -static const uint16_t g_taactu[8] = -{ - /* Units of nanoseconds */ - - 1, /* 0: 1 ns */ - 10, /* 1: 10 ns */ - 100, /* 2: 100 ns */ - - /* Units of microseconds */ - - 1, /* 3: 1 us 1,000 ns */ - 10, /* 4: 10 us 10,000 ns */ - 100, /* 5: 100 us 100,000 ns */ - 1000, /* 6: 1 ms 1,000,000 ns*/ - 10000, /* 7: 10 ms 10,000,000 ns */ -}; - -static const uint16_t g_taactv[] = -{ - 0x000, 0x100, 0x133, 0x14d, /* 0-3: Reserved, 1.0, 1.2, 1.3 */ - 0x180, 0x200, 0x280, 0x300, /* 4-7: 1.5, 2.0, 2.5, 3.0 */ - 0x380, 0x400, 0x480, 0x500, /* 8-11: 3.5, 4.0, 4.5, 5.0 */ - 0x580, 0x600, 0x700, 0x800 /* 12-15: 5.5, 6.0, 7.0, 8.0 */ -}; - -/* Commands *****************************************************************/ - -static const struct mmcsd_cmdinfo_s g_cmd0 = {CMD0, MMCSD_CMDRESP_R1, 0x95}; -static const struct mmcsd_cmdinfo_s g_cmd1 = {CMD1, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd8 = {CMD8, MMCSD_CMDRESP_R7, 0x87}; -static const struct mmcsd_cmdinfo_s g_cmd9 = {CMD9, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd10 = {CMD10, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd12 = {CMD12, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd16 = {CMD16, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd17 = {CMD17, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd18 = {CMD18, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd24 = {CMD24, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd25 = {CMD25, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd55 = {CMD55, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_cmd58 = {CMD58, MMCSD_CMDRESP_R3, 0xff}; -static const struct mmcsd_cmdinfo_s g_acmd23 = {ACMD23, MMCSD_CMDRESP_R1, 0xff}; -static const struct mmcsd_cmdinfo_s g_acmd41 = {ACMD41, MMCSD_CMDRESP_R1, 0xff}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_semtake - ****************************************************************************/ - -static void mmcsd_semtake(sem_t *sem) -{ - while (sem_wait(sem) != 0) - { - /* The only case that an error should occur here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -#define mmcsd_semgive(sem) sem_post(sem) - -/**************************************************************************** - * Name: mmcsd_waitready - * - * Description: - * Wait until the card is no longer busy - * - * Assumptions: - * MMC/SD card already selected - * - ****************************************************************************/ - -static int mmcsd_waitready(FAR struct mmcsd_slot_s *slot) -{ - FAR struct spi_dev_s *spi = slot->spi; - uint8_t response; - uint32_t start; - uint32_t elapsed; - - /* Wait until the card is no longer busy (up to 500MS) */ - - start = START_TIME; - do - { - response = SPI_SEND(spi, 0xff); - if (response == 0xff) - { - return OK; - } - elapsed = ELAPSED_TIME(start); - } - while (elapsed < MMCSD_DELAY_500MS); - - fdbg("Card still busy, last response: %02x\n", response); - return -EBUSY; -} - -/**************************************************************************** - * Name: mmcsd_sendcmd - * - * Description: - * Send a command to MMC - * - * Assumptions: - * MMC/SD card already selected - * - ****************************************************************************/ - -static uint32_t mmcsd_sendcmd(FAR struct mmcsd_slot_s *slot, - const struct mmcsd_cmdinfo_s *cmd, uint32_t arg) -{ - FAR struct spi_dev_s *spi = slot->spi; - uint32_t result; - uint8_t response = 0xff; - int ret; - int i; - - /* Wait until the card is not busy. Some SD cards will not enter the IDLE - * state until CMD0 is sent for the first time, switching the card to SPI - * mode. Having a pull-up resistor on MISO may avoid this problem, but - * this check makes it work also without the pull-up. - */ - - ret = mmcsd_waitready(slot); - if (ret != OK && cmd != &g_cmd0) - { - return ret; - } - - /* Send command code */ - - SPI_SEND(spi, cmd->cmd); - - /* Send command's arguments (should be zero if there are no arguements) */ - - SPI_SEND(spi, (arg >> 24) & 0xff); - SPI_SEND(spi, (arg >> 16) & 0xff); - SPI_SEND(spi, (arg >> 8) & 0xff); - SPI_SEND(spi, arg & 0xff); - - /* Send CRC if needed. The SPI interface is initialized in non-protected - * mode. However, the reset command (CMD0) and CMD8 are received by the - * card while it is still in SD mode and, therefore, must have a valid - * CRC field. - */ - - SPI_SEND(spi, cmd->chksum); - - /* Skip stuff byte on CMD12 */ - - if (cmd->cmd == CMD12) - { - SPI_SEND(spi, 0xff); - } - - /* Get the response to the command. A valid response will have bit7=0. - * Usually, the non-response is 0xff, but I have seen 0xc0 too. - */ - - for (i = 0; i < 9 && (response & 0x80) != 0; i++) - { - response = SPI_SEND(spi, 0xff); - } - - if ((response & 0x80) != 0) - { - fdbg("Failed: i=%d response=%02x\n", i, response); - return (uint32_t)-1; - } - - /* Interpret the response according to the command */ - - result = response; - switch (cmd->resp) - { - /* The R1B response is two bytes long */ - - case MMCSD_CMDRESP_R1B: - { - uint32_t busy = 0; - uint32_t start; - uint32_t elapsed; - - start = START_TIME; - do - { - busy = SPI_SEND(spi, 0xff); - elapsed = ELAPSED_TIME(start); - } - while (elapsed < slot->twrite && busy != 0xff); - - if (busy != 0xff) - { - fdbg("Failed: card still busy (%02x)\n", busy); - return (uint32_t)-1; - } - - fvdbg("CMD%d[%08x] R1B=%02x\n", - cmd->cmd & 0x3f, arg, response); - } - break; - - /* The R1 response is a single byte */ - - case MMCSD_CMDRESP_R1: - { - fvdbg("CMD%d[%08x] R1=%02x\n", - cmd->cmd & 0x3f, arg, response); - } - break; - - /* The R2 response is two bytes long */ - - case MMCSD_CMDRESP_R2: - { - result = ((uint32_t)(response & 0xff) << 8); - result |= SPI_SEND(spi, 0xff) & 0xff; - - fvdbg("CMD%d[%08x] R2=%04x\n", - cmd->cmd & 0x3f, arg, result); - } - break; - - /* The R3 response is 5 bytes long. The first byte is identical to R1. */ - - case MMCSD_CMDRESP_R3: - { - slot->ocr = ((uint32_t)(SPI_SEND(spi, 0xff) & 0xff) << 24); - slot->ocr |= ((uint32_t)(SPI_SEND(spi, 0xff) & 0xff) << 16); - slot->ocr |= ((uint32_t)(SPI_SEND(spi, 0xff) & 0xff) << 8); - slot->ocr |= SPI_SEND(spi, 0xff) & 0xff; - - fvdbg("CMD%d[%08x] R1=%02x OCR=%08x\n", - cmd->cmd & 0x3f, arg, response, slot->ocr); - } - break; - - /* The R7 response is 5 bytes long. The first byte is identical to R1. */ - - case MMCSD_CMDRESP_R7: - default: - { - slot->r7 = ((uint32_t)(SPI_SEND(spi, 0xff) & 0xff) << 24); - slot->r7 |= ((uint32_t)(SPI_SEND(spi, 0xff) & 0xff) << 16); - slot->r7 |= ((uint32_t)(SPI_SEND(spi, 0xff) & 0xff) << 8); - slot->r7 |= SPI_SEND(spi, 0xff) & 0xff; - - fvdbg("CMD%d[%08x] R1=%02x R7=%08x\n", - cmd->cmd & 0x3f, arg, response, slot->r7); - } - break; - } - - return result; -} - -/**************************************************************************** - * Name: mmcsd_setblklen - * - * Description: - * Set block length - * - * Assumptions: - * MMC/SD card already selected - * - ****************************************************************************/ - -static void mmcsd_setblklen(FAR struct mmcsd_slot_s *slot, uint32_t length) -{ - uint32_t response; - - fvdbg("Set block length to %d\n", length); - response = mmcsd_sendcmd(slot, &g_cmd16, length); - if (response != MMCSD_SPIR1_OK) - { - fdbg("Failed to set block length: %02x\n", response); - } -} - -/**************************************************************************** - * Name: mmcsd_nsac - * - * Description: Convert the value of the NSAC to microseconds - * - ****************************************************************************/ - -static uint32_t mmcsd_nsac(FAR struct mmcsd_slot_s *slot, uint8_t *csd, - uint32_t frequency) -{ - /* NSAC is 8-bits wide and is in units of 100 clock cycles. Therefore, the - * maximum value is 25.5K clock cycles. - */ - - uint32_t nsac = MMCSD_CSD_NSAC(csd) * ((uint32_t)100*1000); - uint32_t fhkz = (frequency + 500) / 1000; - return (nsac + (fhkz >> 1)) / fhkz; -} - -/**************************************************************************** - * Name: mmcsd_taac - * - * Description: Convert the value of the TAAC to microseconds - * - ****************************************************************************/ - -static uint32_t mmcsd_taac(FAR struct mmcsd_slot_s *slot, uint8_t *csd) -{ - int tundx; - - /*The TAAC consists of a 3-bit time unit (TU) and a 4-bit time value (TV). - * TAAC is in units of time; NSAC is in units of SPI clocks. - * The access time we need is then given by: - * - * taccess = TU*TV + NSAC/spifrequency - * - * g_taactu holds TU in units of nanoseconds and microseconds (you have to use - * the index to distiguish. g_taactv holds TV with 8-bits of fraction. - */ - - tundx = MMCSD_CSD_TAAC_TIMEUNIT(csd); - if (tundx <= MAX_USTUNDX) - { - /* The maximum value of the nanosecond TAAC is 800 ns. The rounded - * answer in microseconds will be at most 1. - */ - - return 1; - } - else - { - /* Return the answer in microseconds */ - - return (g_taactu[tundx]*g_taactv[MMCSD_CSD_TAAC_TIMEVALUE(csd)] + 0x80) >> 8; - } -} - -/**************************************************************************** - * Name: mmcsd_decodecsd - * - * Description: - * - ****************************************************************************/ - -static void mmcsd_decodecsd(FAR struct mmcsd_slot_s *slot, uint8_t *csd) -{ - FAR struct spi_dev_s *spi = slot->spi; - uint32_t maxfrequency; - uint32_t frequency; - uint32_t readbllen; - uint32_t csizemult; - uint32_t csize; - - /* Calculate SPI max clock */ - - maxfrequency = - g_transpeedtu[MMCSD_CSD_TRANSPEED_TIMEVALUE(csd)] * - g_transpeedru[MMCSD_CSD_TRANSPEED_TRANSFERRATEUNIT(csd)]; - - /* Clip the max frequency to account for board limitations */ - - frequency = maxfrequency; - if (frequency > CONFIG_MMCSD_SPICLOCK) - { - frequency = CONFIG_MMCSD_SPICLOCK; - } - - /* Set the actual SPI frequency as close as possible to that value */ - - frequency = SPI_SETFREQUENCY(spi, frequency); - - /* Now determine the delay to access data */ - - if (slot->type == MMCSD_CARDTYPE_MMC) - { - /* The TAAC consists of a 3-bit time unit (TU) and a 4-bit time value (TV). - * TAAC is in units of time; NSAC is in units of SPI clocks. - * The access time we need is then given by: - * - * taccess = TU*TV + NSAC/spifrequency - * - * Example: TAAC = 1.5 ms, NSAC = 0, r2wfactor = 4, CLK_TCK=100 - * taccessus = 1,500uS - * taccess = (1,500 * 100) / 100,000) + 1 = 2 (ideal, 1.5) - * twrite = (1,500 * 4 * 100) / 100,000) + 1 = 7 (ideal 6.0) - * - * First get the access time in microseconds - */ - - uint32_t taccessus = mmcsd_taac(slot, csd) + mmcsd_nsac(slot, csd, frequency); - - /* Then convert to system clock ticks. The maximum read access is 10 times - * the tacc value: taccess = 10 * (taccessus / 1,000,000) * CLK_TCK, or - */ - - slot->taccess = (taccessus * CLK_TCK) / 100000 + 1; - - /* NOTE that we add one to taccess to assure that we wait at least this - * time. The write access time is larger by the R2WFACTOR: */ - - slot->taccess = (taccessus * MMCSD_CSD_R2WFACTOR(csd) * CLK_TCK) / 100000 + 1; - } - else - { - /* For SD, the average is still given by the TAAC+NSAC, but the - * maximum are the constants 100 and 250MS - */ - - slot->taccess = SD_READACCESS; - slot->twrite = SD_WRITEACCESS; - } - - fvdbg("SPI Frequency\n"); - fvdbg(" Maximum: %d Hz\n", maxfrequency); - fvdbg(" Actual: %d Hz\n", frequency); - fvdbg("Read access time: %d ticks\n", slot->taccess); - fvdbg("Write access time: %d ticks\n", slot->twrite); - - /* Get the physical geometry of the card: sector size and number of - * sectors. The card's total capacity is computed from - * - * capacity = BLOCKNR * BLOCK_LEN - * BLOCKNR = (C_SIZE+1)*MULT - * MULT = 2**(C_SIZE_MULT+2) (C_SIZE_MULT < 8) - * BLOCK_LEN = 2**READ_BL_LEN (READ_BL_LEN < 12) - * - * Or - * - * capacity = ((C_SIZE+1) << (READD_BL_LEN + C_SIZE_MULT + 2)) - * - * In units of the sector size (1 << READ_BL_LEN), then simplifies to - * - * nsectors = ((C_SIZE+1) << (C_SIZE_MULT + 2)) - */ - - if (MMCSD_CSD_CSDSTRUCT(csd) != 0) - { - /* SDC structure ver 2.xx */ - /* Note: On SD card WRITE_BL_LEN is always the same as READ_BL_LEN */ - - readbllen = SD20_CSD_READBLLEN(csd); - csizemult = SD20_CSD_CSIZEMULT(csd) + 2; - csize = SD20_CSD_CSIZE(csd) + 1; - } - else - { - /* MMC or SD structure ver 1.xx */ - /* Note: On SD card WRITE_BL_LEN is always the same as READ_BL_LEN */ - - readbllen = MMCSD_CSD_READBLLEN(csd); - csizemult = MMCSD_CSD_CSIZEMULT(csd) + 2; - csize = MMCSD_CSD_CSIZE(csd) + 1; - } - - /* SDHC ver2.x cards have fixed block transfer size of 512 bytes. SDC - * ver1.x cards with capacity less than 1Gb, will have sector size - * 512 byes. SDC ver1.x cards with capacity of 2Gb will report readbllen - * of 1024 but should use 512 bytes for block transfers. SDC ver1.x 4Gb - * cards will report readbllen of 2048 bytes -- are they also 512 bytes? - */ - -#ifdef CONFIG_MMCSD_SECTOR512 - if (readbllen > 9) - { - csizemult += (readbllen - 9); - } - else - { - DEBUGASSERT(readbllen == 9); - } -#else - if (IS_SDV2(slot->type)) - { - if (readbllen > 9) - { - fdbg("Forcing 512 byte sector size\n"); - csizemult += (readbllen - 9); - readbllen = 9; - } - } - - slot->sectorsize = 1 << readbllen; -#endif - slot->nsectors = csize << csizemult; - fvdbg("Sector size: %d\n", SECTORSIZE(slot)); - fvdbg("Number of sectors: %d\n", slot->nsectors); -} - -/**************************************************************************** - * Name: mmcsd_checkwrprotect - * - * Description: - * - ****************************************************************************/ - -static void mmcsd_checkwrprotect(FAR struct mmcsd_slot_s *slot, uint8_t *csd) -{ - FAR struct spi_dev_s *spi = slot->spi; - - /* Check if (1) the slot is reporting that reporting that write protection - * is set, (2) the card reports permanent write protect, or (2) the card - * reports temporary write protect. - */ - - if ((SPI_STATUS(spi, SPIDEV_MMCSD) & SPI_STATUS_WRPROTECTED) != 0 || - MMCSD_CSD_PERMWRITEPROTECT(csd) || - MMCSD_CSD_TMPWRITEPROTECT(csd)) - { - slot->state |= MMCSD_SLOTSTATUS_WRPROTECT; - } - else - { - slot->state &= ~MMCSD_SLOTSTATUS_WRPROTECT; - } -} - -/**************************************************************************** - * Name: mmcsd_getcardinfo - * - * Description: - * Read CSD or CID registers - * - * Assumptions: - * MMC/SD card already selected - * - ****************************************************************************/ - -static int mmcsd_getcardinfo(FAR struct mmcsd_slot_s *slot, uint8_t *buffer, - const struct mmcsd_cmdinfo_s *cmd) -{ - FAR struct spi_dev_s *spi = slot->spi; - uint32_t result; - uint8_t response; - int i; - - SPI_SEND(spi, 0xff); - - /* Send the CMD9 or CMD10 */ - - result = mmcsd_sendcmd(slot, cmd, 0); - if (result != MMCSD_SPIR1_OK) - { - fdbg("CMD9/10 failed: R1=%02x\n", result); - return -EIO; - } - - /* Try up to 8 times to find the start of block (or until an error occurs) */ - - for (i = 0; i < 8; i++) - { - response = SPI_SEND(spi, 0xff); - fvdbg("%d. SPI send returned %02x\n", i, response); - - /* If a read operation fails and the card cannot provide the requested - * data, it will send a data error token instead. The 4 least - * significant bits are the same as those in the R2 response. - */ - - if (response != 0 && (response & MMCSD_SPIDET_UPPER) == 0) - { - fdbg("%d. Data transfer error: %02x\n", i, response); - return -EIO; - } - else if (response == MMCSD_SPIDT_STARTBLKSNGL) - { - for (i = 0; i < 16; ++i) - { - *buffer++ = SPI_SEND(spi, 0xff); - } - - /* CRC receive */ - - SPI_SEND(spi, 0xff); - SPI_SEND(spi, 0xff); - return OK; - } - } - - fdbg("%d. Did not find start of block\n"); - return -EIO; -} - -/**************************************************************************** - * Name: mmcsd_recvblock - * - * Description: Receive a data block from the card - * - ****************************************************************************/ - -static int mmcsd_recvblock(FAR struct mmcsd_slot_s *slot, uint8_t *buffer, int nbytes) -{ - FAR struct spi_dev_s *spi = slot->spi; - uint32_t start; - uint32_t elapsed; - uint8_t token; - - /* Wait up to the maximum to receive a valid data token. taccess is the - * time from when the command is sent until the first byte of data is - * received */ - - start = START_TIME; - do - { - token = SPI_SEND(spi, 0xff); - elapsed = ELAPSED_TIME(start); - } - while (token == 0xff && elapsed < slot->taccess); - - if (token == MMCSD_SPIDT_STARTBLKSNGL) - { - /* Receive the block */ - - SPI_RECVBLOCK(spi, buffer, nbytes); - - /* Discard the CRC */ - - SPI_SEND(spi, 0xff); - SPI_SEND(spi, 0xff); - return OK; - } - - fdbg("Did not receive data token (%02x)\n", token); - return ERROR; -} - -/**************************************************************************** - * Name: mmcsd_xmitblock - * - * Description: Transmit a data block to the card - * - ****************************************************************************/ - -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_READONLY) -static int mmcsd_xmitblock(FAR struct mmcsd_slot_s *slot, const uint8_t *buffer, - int nbytes, uint8_t token) -{ - FAR struct spi_dev_s *spi = slot->spi; - uint8_t response; - - /* Start the block transfer: - * 1. 0xff (sync) - * 2. 0xfe or 0xfc (start of block token) - * 3. Followed by the block of data and 2 byte CRC - */ - - SPI_SEND(spi, 0xff); /* sync */ - SPI_SEND(spi, token); /* data token */ - - /* Transmit the block to the MMC/SD card */ - - (void)SPI_SNDBLOCK(spi, buffer, nbytes); - - /* Add the bogus CRC. By default, the SPI interface is initialized in - * non-protected mode. However, we still have to send bogus CRC values - */ - - SPI_SEND(spi, 0xff); - SPI_SEND(spi, 0xff); - - /* Now get the data response */ - - response = SPI_SEND(spi, 0xff); - if ((response & MMCSD_SPIDR_MASK) != MMCSD_SPIDR_ACCEPTED) - { - fdbg("Bad data response: %02x\n", response); - return -EIO; - } - return OK; -} -#endif /* CONFIG_FS_WRITABLE && !CONFIG_MMCSD_READONLY */ - -/**************************************************************************** - * Block Driver Operations - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_open - * - * Description: Open the block device - * - ****************************************************************************/ - -static int mmcsd_open(FAR struct inode *inode) -{ - FAR struct mmcsd_slot_s *slot; - FAR struct spi_dev_s *spi; - int ret; - - fvdbg("Entry\n"); - -#ifdef CONFIG_DEBUG - if (!inode || !inode->i_private) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Extract our private data from the inode structure */ - - slot = (FAR struct mmcsd_slot_s *)inode->i_private; - spi = slot->spi; - -#ifdef CONFIG_DEBUG - if (!spi) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Verify that an MMC/SD card has been inserted */ - - ret = -ENODEV; - mmcsd_semtake(&slot->sem); - if ((SPI_STATUS(spi, SPIDEV_MMCSD) & SPI_STATUS_PRESENT) != 0) - { - /* Yes.. a card is present. Has it been initialized? */ - - if (slot->type == MMCSD_CARDTYPE_UNKNOWN) - { - /* Ininitialize for the media in the slot */ - - ret = mmcsd_mediainitialize(slot); - if (ret < 0) - { - fvdbg("Failed to initialize card\n"); - goto errout_with_sem; - } - } - - /* Make sure that the card is ready */ - - SPI_SELECT(spi, SPIDEV_MMCSD, true); - ret = mmcsd_waitready(slot); - SPI_SELECT(spi, SPIDEV_MMCSD, false); - } - -errout_with_sem: - mmcsd_semgive(&slot->sem); - return ret; -} - -/**************************************************************************** - * Name: mmcsd_close - * - * Description: close the block device - * - ****************************************************************************/ - -static int mmcsd_close(FAR struct inode *inode) -{ - fvdbg("Entry\n"); - return OK; -} - -/**************************************************************************** - * Name: mmcsd_read - * - * Description: Read the specified numer of sectors - * - ****************************************************************************/ - -static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - FAR struct mmcsd_slot_s *slot; - FAR struct spi_dev_s *spi; - size_t nbytes; - off_t offset; - uint8_t response; - int i; - - fvdbg("start_sector=%d nsectors=%d\n", start_sector, nsectors); - -#ifdef CONFIG_DEBUG - if (!buffer) - { - fdbg("Invalid parameters\n"); - return -EINVAL; - } - - if (!inode || !inode->i_private) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Extract our private data from the inode structure */ - - slot = (FAR struct mmcsd_slot_s *)inode->i_private; - spi = slot->spi; - -#ifdef CONFIG_DEBUG - if (!spi) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Verify that card is available */ - - if (slot->state & MMCSD_SLOTSTATUS_NOTREADY) - { - fdbg("Slot not ready\n"); - return -ENODEV; - } - - /* Do nothing on zero-length transfer */ - - if (nsectors < 1) - { - return 0; - } - - /* Convert sector and nsectors to nbytes and byte offset */ - - nbytes = nsectors * SECTORSIZE(slot); - if (IS_BLOCK(slot->type)) - { - offset = start_sector; - fvdbg("nbytes=%d sector offset=%d\n", nbytes, offset); - } - else - { - offset = start_sector * SECTORSIZE(slot); - fvdbg("nbytes=%d byte offset=%d\n", nbytes, offset); - } - - /* Select the slave */ - - mmcsd_semtake(&slot->sem); - SPI_SELECT(spi, SPIDEV_MMCSD, true); - - /* Single or multiple block read? */ - - if (nsectors == 1) - { - /* Send CMD17: Reads a block of the size selected by the SET_BLOCKLEN - * command and verify that good R1 status is returned - */ - - response = mmcsd_sendcmd(slot, &g_cmd17, offset); - if (response != MMCSD_SPIR1_OK) - { - fdbg("CMD17 failed: R1=%02x\n", response); - goto errout_with_eio; - } - - /* Receive the block */ - - if (mmcsd_recvblock(slot, buffer, SECTORSIZE(slot)) != 0) - { - fdbg("Failed: to receive the block\n"); - goto errout_with_eio; - } - } - else - { - /* Send CMD18: Reads a block of the size selected by the SET_BLOCKLEN - * command and verify that good R1 status is returned - */ - - response = mmcsd_sendcmd(slot, &g_cmd18, offset); - if (response != MMCSD_SPIR1_OK) - { - fdbg("CMD118 failed: R1=%02x\n", response); - goto errout_with_eio; - } - - /* Receive each block */ - - for (i = 0; i < nsectors; i++) - { - if (mmcsd_recvblock(slot, buffer, SECTORSIZE(slot)) != 0) - { - fdbg("Failed: to receive the block\n"); - goto errout_with_eio; - } - buffer += SECTORSIZE(slot); - } - - /* Send CMD12: Stops transmission */ - - response = mmcsd_sendcmd(slot, &g_cmd12, 0); - } - - /* On success, return the number of sectors transfer */ - - SPI_SELECT(spi, SPIDEV_MMCSD, false); - SPI_SEND(spi, 0xff); - mmcsd_semgive(&slot->sem); - - fvdbg("Read %d bytes:\n", nbytes); - mmcsd_dumpbuffer("Read buffer", buffer, nbytes); - return nsectors; - -errout_with_eio: - SPI_SELECT(spi, SPIDEV_MMCSD, false); - mmcsd_semgive(&slot->sem); - return -EIO; -} - -/**************************************************************************** - * Name: mmcsd_write - * - * Description: - * Write the specified number of sectors - * - ****************************************************************************/ - -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_READONLY) -static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - FAR struct mmcsd_slot_s *slot; - FAR struct spi_dev_s *spi; - size_t nbytes; - off_t offset; - uint8_t response; - int ret; - int i; - - fvdbg("start_sector=%d nsectors=%d\n", start_sector, nsectors); - -#ifdef CONFIG_DEBUG - if (!buffer) - { - fdbg("Invalid parameters\n"); - return -EINVAL; - } - - if (!inode || !inode->i_private) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Extract our private data from the inode structure */ - - slot = (FAR struct mmcsd_slot_s *)inode->i_private; - spi = slot->spi; - -#ifdef CONFIG_DEBUG - if (!spi) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Verify that card is available */ - - if (slot->state & MMCSD_SLOTSTATUS_NOTREADY) - { - fdbg("Slot not ready\n"); - return -ENODEV; - } - - /* Verify that the card is write enabled */ - - if (slot->state & MMCSD_SLOTSTATUS_WRPROTECT) - { - fdbg("Not write enabled\n"); - return -EACCES; - } - - /* Do nothing on zero-length transfer */ - - if (nsectors < 1) - { - return 0; - } - - /* Convert sector and nsectors to nbytes and byte offset */ - - nbytes = nsectors * SECTORSIZE(slot); - if (IS_BLOCK(slot->type)) - { - offset = start_sector; - fvdbg("nbytes=%d sector offset=%d\n", nbytes, offset); - } - else - { - offset = start_sector * SECTORSIZE(slot); - fvdbg("nbytes=%d byte offset=%d\n", nbytes, offset); - } - mmcsd_dumpbuffer("Write buffer", buffer, nbytes); - - /* Select the slave */ - - mmcsd_semtake(&slot->sem); - SPI_SELECT(spi, SPIDEV_MMCSD, true); - - /* Single or multiple block transfer? */ - - if (nsectors == 1) - { - /* Send CMD24 (WRITE_BLOCK) and verify that good R1 status is returned */ - - response = mmcsd_sendcmd(slot, &g_cmd24, offset); - if (response != MMCSD_SPIR1_OK) - { - fdbg("CMD24 failed: R1=%02x\n", response); - goto errout_with_sem; - } - - /* Then transfer the sector */ - - if (mmcsd_xmitblock(slot, buffer, SECTORSIZE(slot), 0xfe) != 0) - { - fdbg("Block transfer failed\n"); - goto errout_with_sem; - } - } - else - { - /* Set the number of blocks to be pre-erased (SD only) */ - - if (IS_SD(slot->type)) - { - response = mmcsd_sendcmd(slot, &g_acmd23, nsectors); - if (response != MMCSD_SPIR1_OK) - { - fdbg("ACMD23 failed: R1=%02x\n", response); - goto errout_with_sem; - } - } - - /* Send CMD25: Continuously write blocks of data until the - * tranmission is stopped. - */ - - response = mmcsd_sendcmd(slot, &g_cmd25, offset); - if (response != MMCSD_SPIR1_OK) - { - fdbg("CMD25 failed: R1=%02x\n", response); - goto errout_with_sem; - } - - /* Transmit each block */ - - for (i = 0; i < nsectors; i++) - { - if (mmcsd_xmitblock(slot, buffer, SECTORSIZE(slot), 0xfc) != 0) - { - fdbg("Failed: to receive the block\n"); - goto errout_with_sem; - } - buffer += SECTORSIZE(slot); - } - - /* Send the stop transmission token */ - - SPI_SEND(spi, MMCSD_SPIDT_STOPTRANS); - } - - /* Wait until the card is no longer busy */ - - ret = mmcsd_waitready(slot); - SPI_SELECT(spi, SPIDEV_MMCSD, false); - SPI_SEND(spi, 0xff); - mmcsd_semgive(&slot->sem); - - /* The success return value is the number of sectors written */ - - return nsectors; - -errout_with_sem: - SPI_SELECT(spi, SPIDEV_MMCSD, false); - mmcsd_semgive(&slot->sem); - return -EIO; -} -#endif - -/**************************************************************************** - * Name: mmcsd_geometry - * - * Description: - * Return device geometry - * - ****************************************************************************/ - -static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry) -{ - FAR struct mmcsd_slot_s *slot; - FAR struct spi_dev_s *spi; - uint8_t csd[16]; - int ret; - -#ifdef CONFIG_DEBUG - if (!geometry) - { - fdbg("Invalid parameters\n"); - return -EINVAL; - } - - if (!inode || !inode->i_private) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Extract our private data from the inode structure */ - - slot = (FAR struct mmcsd_slot_s *)inode->i_private; - spi = slot->spi; - -#ifdef CONFIG_DEBUG - if (!spi) - { - fdbg("Internal confusion\n"); - return -EIO; - } -#endif - - /* Re-sample the CSD */ - - mmcsd_semtake(&slot->sem); - SPI_SELECT(spi, SPIDEV_MMCSD, true); - ret = mmcsd_getcsd(slot, csd); - SPI_SELECT(spi, SPIDEV_MMCSD, false); - - if (ret < 0) - { - mmcsd_semgive(&slot->sem); - fdbg("mmcsd_getcsd returned %d\n", ret); - return ret; - } - - /* Check for changes related to write protection */ - - mmcsd_checkwrprotect(slot, csd); - - /* Then return the card geometry */ - - geometry->geo_available = - ((slot->state & (MMCSD_SLOTSTATUS_NOTREADY|MMCSD_SLOTSTATUS_NODISK)) == 0); - geometry->geo_mediachanged = - ((slot->state & MMCSD_SLOTSTATUS_MEDIACHGD) != 0); -#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_READONLY) - geometry->geo_writeenabled = - ((slot->state & MMCSD_SLOTSTATUS_WRPROTECT) == 0); -#else - geometry->geo_writeenabled = false; -#endif - geometry->geo_nsectors = slot->nsectors; - geometry->geo_sectorsize = SECTORSIZE(slot); - - /* After reporting mediachanged, clear the indication so that it is not - * reported again. - */ - - slot->state &= ~MMCSD_SLOTSTATUS_MEDIACHGD; - mmcsd_semgive(&slot->sem); - - fvdbg("geo_available: %d\n", geometry->geo_available); - fvdbg("geo_mediachanged: %d\n", geometry->geo_mediachanged); - fvdbg("geo_writeenabled: %d\n", geometry->geo_writeenabled); - fvdbg("geo_nsectors: %d\n", geometry->geo_nsectors); - fvdbg("geo_sectorsize: %d\n", geometry->geo_sectorsize); - - return OK; -} - -/**************************************************************************** - * Initialization - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_mediainitialize - * - * Description: - * Detect media and initialize - * - ****************************************************************************/ - -static int mmcsd_mediainitialize(FAR struct mmcsd_slot_s *slot) -{ - FAR struct spi_dev_s *spi = slot->spi; - uint8_t csd[16]; - uint32_t result = MMCSD_SPIR1_IDLESTATE; - uint32_t start; - uint32_t elapsed; - int i, j; - - /* Assume that the card is not ready (we'll clear this on successful card - * initialization. - */ - - slot->state |= MMCSD_SLOTSTATUS_NOTREADY; - - /* Check if there is a card present in the slot. This is normally a matter is - * of GPIO sensing and does not really involve SPI, but by putting this - * functionality in the SPI interface, we encapuslate the SPI MMC/SD - * interface - */ - - if ((SPI_STATUS(spi, SPIDEV_MMCSD) & SPI_STATUS_PRESENT) == 0) - { - fdbg("No card present\n"); - slot->state |= MMCSD_SLOTSTATUS_NODISK; - return -ENODEV; - } - - /* Clock Freq. Identification Mode < 400kHz */ - - SPI_SETFREQUENCY(spi, MMCSD_IDMODE_CLOCK); - - /* Set the maximum access time out */ - - slot->taccess = SD_READACCESS; - - /* The SD card wakes up in SD mode. It will enter SPI mode if the chip select signal is - * asserted (negative) during the reception of the reset command (CMD0) and the card is in - * IDLE state. - */ - - for (i = 0; i < 2; i++) - { - /* After power up at least 74 clock cycles are required prior to - * starting bus communication - */ - - for (j = 10; j; j--) - { - SPI_SEND(spi, 0xff); - } - - /* Send CMD0 (GO_TO_IDLE) with CS asserted to put MMC/SD in - * IDLE/SPI mode. Return from CMD0 is R1 which should now - * show IDLE STATE - */ - - fvdbg("Send CMD0\n"); - SPI_SELECT(spi, SPIDEV_MMCSD, true); - result = mmcsd_sendcmd(slot, &g_cmd0, 0); - if (result == MMCSD_SPIR1_IDLESTATE) - { - /* Break out of the loop with card selected */ - - fvdbg("Card is in IDLE state\n"); - break; - } - - /* De-select card and try again */ - - SPI_SELECT(spi, SPIDEV_MMCSD, false); - } - - /* Verify that we exit the above loop with the card reporting IDLE state */ - - if (result != MMCSD_SPIR1_IDLESTATE) - { - fdbg("Send CMD0 failed: R1=%02x\n", result); - SPI_SELECT(spi, SPIDEV_MMCSD, false); - return -EIO; - } - - slot->type = MMCSD_CARDTYPE_UNKNOWN; - - /* Check for SDHC Version 2.x. CMD 8 is reserved on SD version 1.0 and MMC. */ - - fvdbg("Send CMD8\n"); - result = mmcsd_sendcmd(slot, &g_cmd8, 0x1aa); - if (result == MMCSD_SPIR1_IDLESTATE) - { - /* Verify the operating voltage and that the 0xaa was correctly echoed */ - - if (((slot->r7 & MMCSD_SPIR7_VOLTAGE_MASK) == MMCSD_SPIR7_VOLTAGE_27) && - ((slot->r7 & MMCSD_SPIR7_ECHO_MASK) == 0xaa)) - { - /* Try CMD55/ACMD41 for up to 1 second or until the card exits - * the IDLE state - */ - - start = START_TIME; - elapsed = 0; - do - { - fvdbg("%d. Send CMD55/ACMD41\n", elapsed); - result = mmcsd_sendcmd(slot, &g_cmd55, 0); - if (result == MMCSD_SPIR1_IDLESTATE || result == MMCSD_SPIR1_OK) - { - result = mmcsd_sendcmd(slot, &g_acmd41, (uint32_t)1 << 30); - if (result == MMCSD_SPIR1_OK) - { - break; - } - } - elapsed = ELAPSED_TIME(start); - } - while (elapsed < MMCSD_DELAY_1SEC); - - /* Check if ACMD41 was sent successfully */ - - if (elapsed < MMCSD_DELAY_1SEC) - { - fvdbg("Send CMD58\n"); - SPI_SEND(spi, 0xff); - result = mmcsd_sendcmd(slot, &g_cmd58, 0); - if (result == MMCSD_SPIR1_OK) - { - fvdbg("OCR: %08x\n", slot->ocr); - if ((slot->ocr & MMCSD_OCR_CCS) != 0) - { - fdbg("Identified SD ver2 card/with block access\n"); - slot->type = MMCSD_CARDTYPE_SDV2|MMCSD_CARDTYPE_BLOCK; - } - else - { - fdbg("Identified SD ver2 card\n"); - slot->type = MMCSD_CARDTYPE_SDV2; - } - } - } - } - } - - /* Check for SDC version 1.x or MMC */ - - else - { - /* Both the MMC card and the SD card support CMD55 */ - - fvdbg("Send CMD55/ACMD41\n"); - result = mmcsd_sendcmd(slot, &g_cmd55, 0); - if (result == MMCSD_SPIR1_IDLESTATE || result == MMCSD_SPIR1_OK) - { - /* But ACMD41 is supported only on SD */ - - result = mmcsd_sendcmd(slot, &g_acmd41, 0); - if (result == MMCSD_SPIR1_IDLESTATE || result == MMCSD_SPIR1_OK) - { - fdbg("Identified SD ver1 card\n"); - slot->type = MMCSD_CARDTYPE_SDV1; - } - } - - /* Make sure that we are out of the Idle state */ - - start = START_TIME; - elapsed = 0; - do - { - if (IS_SD(slot->type)) - { - fvdbg("%d. Send CMD55/ACMD41\n", elapsed); - result = mmcsd_sendcmd(slot, &g_cmd55, 0); - if (result == MMCSD_SPIR1_IDLESTATE || result == MMCSD_SPIR1_OK) - { - result = mmcsd_sendcmd(slot, &g_acmd41, 0); - if (result == MMCSD_SPIR1_OK) - { - break; - } - } - } - else - { - fvdbg("%d. Send CMD1\n", i); - result = mmcsd_sendcmd(slot, &g_cmd1, 0); - if (result == MMCSD_SPIR1_OK) - { - fdbg("%d. Identified MMC card\n", i); - slot->type = MMCSD_CARDTYPE_MMC; - break; - } - } - elapsed = ELAPSED_TIME(start); - } - while (elapsed < MMCSD_DELAY_1SEC); - - if (elapsed >= MMCSD_DELAY_1SEC) - { - fdbg("Failed to exit IDLE state\n"); - SPI_SELECT(spi, SPIDEV_MMCSD, false); - return -EIO; - } - } - - if (slot->type == MMCSD_CARDTYPE_UNKNOWN) - { - fdbg("Failed to identify card\n"); - SPI_SELECT(spi, SPIDEV_MMCSD, false); - return -EIO; - } - - /* Read CSD. CSD must always be valid */ - - fvdbg("Get CSD\n"); - result = mmcsd_getcsd(slot, csd); - if (result != OK) - { - fdbg("mmcsd_getcsd(CMD9) failed: %d\n", result); - SPI_SELECT(spi, SPIDEV_MMCSD, false); - return -EIO; - } - mmcsd_dmpcsd(csd, slot->type); - - /* CSD data and set block size */ - - mmcsd_decodecsd(slot, csd); - mmcsd_checkwrprotect(slot, csd); - - /* SDHC ver2.x cards have fixed block transfer size of 512 bytes. SDC - * ver1.x cards with capacity less than 1Gb, will have sector size - * 512 byes. SDC ver1.x cards with capacity of 2Gb will report readbllen - * of 1024 but should use 512 bytes for block transfers. SDC ver1.x 4Gb - * cards will report readbllen of 2048 bytes -- are they also 512 bytes? - * I think that none of these high capacity cards support setting the - * block length?? - */ - -#ifdef CONFIG_MMCSD_SECTOR512 - /* Using 512 byte sectors, the maximum ver1.x capacity is 4096 x 512 blocks. - * The saved slot->nsectors is converted to 512 byte blocks, so if slot->nsectors - * exceeds 4096 x 512, then we must be dealing with a card with read_bl_len - * of 1024 or 2048. - */ - - if (!IS_SDV2(slot->type) && slot->nsectors <= ((uint32_t)4096*12)) - { - /* Don't set the block len on high capacity cards (ver1.x or ver2.x) */ - - mmcsd_setblklen(slot, SECTORSIZE(slot)); - } -#else - if (!IS_SDV2(slot->type)) - { - /* Don't set the block len on ver2.x cards */ - - mmcsd_setblklen(slot, SECTORSIZE(slot)); - } -#endif - - slot->state &= ~MMCSD_SLOTSTATUS_NOTREADY; - SPI_SELECT(spi, SPIDEV_MMCSD, false); - return OK; -} - -/**************************************************************************** - * Name: mmcsd_mediachanged - * - * Description: - * Handle initialization/media change events - * - ****************************************************************************/ - -static void mmcsd_mediachanged(void *arg) -{ - struct mmcsd_slot_s *slot = (struct mmcsd_slot_s*)arg; - FAR struct spi_dev_s *spi; - uint8_t oldstate; - int ret; - -#ifdef CONFIG_DEBUG - if (!slot || !slot->spi) - { - fdbg("Internal confusion\n"); - return; - } -#endif - spi = slot->spi; - - /* Save the current slot state and reassess the new state */ - - mmcsd_semtake(&slot->sem); - oldstate = slot->state; - - /* Check if media was removed or inserted */ - - slot->state &= ~(MMCSD_SLOTSTATUS_NODISK|MMCSD_SLOTSTATUS_NOTREADY|MMCSD_SLOTSTATUS_MEDIACHGD); - if ((SPI_STATUS(spi, SPIDEV_MMCSD) & SPI_STATUS_PRESENT) == 0) - { - /* Media is not present */ - - fdbg("No card present\n"); - slot->state |= (MMCSD_SLOTSTATUS_NODISK|MMCSD_SLOTSTATUS_NOTREADY); - - /* Was media removed? */ - - if ((oldstate & MMCSD_SLOTSTATUS_NODISK) == 0) - { - slot->state |= MMCSD_SLOTSTATUS_MEDIACHGD; - } - } - - /* Media is present, was it just inserted? Or, if it was previously not ready, - * then try re-initializing it - */ - - else if ((oldstate & (MMCSD_SLOTSTATUS_NODISK|MMCSD_SLOTSTATUS_NOTREADY)) != 0) - { - /* (Re-)ininitialize for the media in the slot */ - - ret = mmcsd_mediainitialize(slot); - if (ret == 0) - { - fvdbg("mmcsd_mediainitialize returned OK\n"); - slot->state |= MMCSD_SLOTSTATUS_MEDIACHGD; - } - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mmcsd_spislotinitialize - * - * Description: - * Initialize one slot for operation using the SPI MMC/SD interface - * - * Input Parameters: - * minor - The MMC/SD minor device number. The MMC/SD device will be - * registered as /dev/mmcsdN where N is the minor number - * slotno - The slot number to use. This is only meaningful for architectures - * that support multiple MMC/SD slots. This value must be in the range - * {0, ..., CONFIG_MMCSD_NSLOTS}. - * spi - And instance of an SPI interface obtained by called - * up_spiinitialize() with the appropriate port number (see spi.h) - * - ****************************************************************************/ - -int mmcsd_spislotinitialize(int minor, int slotno, FAR struct spi_dev_s *spi) -{ - struct mmcsd_slot_s *slot; - char devname[16]; - int ret; - -#ifdef CONFIG_DEBUG - if ((unsigned)slotno >= CONFIG_MMCSD_NSLOTS || (unsigned)minor > 255 || !spi) - { - fdbg("Invalid arguments\n"); - return -EINVAL; - } -#endif - - /* Select the slot structure */ - - slot = &g_mmcsdslot[slotno]; - memset(slot, 0, sizeof(struct mmcsd_slot_s)); - sem_init(&slot->sem, 0, 1); - -#ifdef CONFIG_DEBUG - if (slot->spi) - { - fdbg("Already registered\n"); - return -EBUSY; - } -#endif - - /* Bind the SPI port to the slot */ - - slot->spi = spi; - - /* Ininitialize for the media in the slot (if any) */ - - ret = mmcsd_mediainitialize(slot); - if (ret == 0) - { - fvdbg("mmcsd_mediainitialize returned OK\n"); - slot->state |= MMCSD_SLOTSTATUS_MEDIACHGD; - } - - /* Create a MMC/SD device name */ - - snprintf(devname, 16, "/dev/mmcsd%d", minor); - - /* Register the driver, even on a failure condition. A - * card may be inserted later, for example. - */ - - ret = register_blockdriver(devname, &g_bops, MMCSD_MODE, slot); - if (ret < 0) - { - fdbg("register_blockdriver failed: %d\n", -ret); - slot->spi = NULL; - return ret; - } - - /* Register a media change callback to handler insertion and - * removal of cards. - */ - - (void)SPI_REGISTERCALLBACK(spi, mmcsd_mediachanged, (void*)slot); - return OK; -} - -#endif /* defined (CONFIG_MMCSD) && defined (CONFIG_MMCSD_SPI) */ diff --git a/nuttx/drivers/mmcsd/mmcsd_spi.h b/nuttx/drivers/mmcsd/mmcsd_spi.h deleted file mode 100644 index 8c6f9bae7..000000000 --- a/nuttx/drivers/mmcsd/mmcsd_spi.h +++ /dev/null @@ -1,187 +0,0 @@ -/**************************************************************************** - * drivers/mmcsd/mmcsd_spi.h - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_MMCSD_MMCSD_SPI_H -#define __DRIVERS_MMCSD_MMCSD_SPI_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -/**************************************************************************** - * Pre-Processor Definitions - ****************************************************************************/ - -/* SPI *******************************************************************/ - -/* SPI Command Set */ - -#define CMD0 0x40 /* GO_IDLE_STATE: Resets all cards to idle state */ -#define CMD1 0x41 /* SEND_OP_COND: Sends capacity support information */ -#define CMD6 0x46 /* SWITCH_FUNC: Checks switchable function */ -#define CMD8 0x48 /* SEND_IF_COND: Sends SD Memory Card interface condition */ -#define CMD9 0x49 /* SEND_CSD: Asks card to send its card specific data (CSD) */ -#define CMD10 0x4a /* SEND_CID: Asks card to send its card identification (CID) */ -#define CMD12 0x4c /* STOP_TRANSMISSION: Forces the card to stop transmission */ -#define CMD13 0x4d /* SEND_STATUS: Asks card to send its status register */ -#define CMD16 0x50 /* SET_BLOCKLEN: Sets a block length (in bytes) */ -#define CMD17 0x51 /* READ_SINGLE_BLOCK: Reads a block of the selected size */ -#define CMD18 0x52 /* READ_MULTIPLE_BLOCK: Continuously transfers blocks from card to host */ -#define CMD20 0x54 /* CMD_WRITEBLOCK: Write block to memory (MMC) */ -#define CMD24 0x58 /* WRITE_BLOCK: Writes a block of the selected size */ -#define CMD25 0x59 /* WRITE_MULTIPLE_BLOCK: Continuously writes blocks of data */ -#define CMD27 0x5b /* PROGRAM_CSD: Set programmable bits of the CSD */ -#define CMD28 0x5c /* SET_WRITE_PROT: Sets the write protection bit of group */ -#define CMD29 0x5d /* CLR_WRITE_PROT: Clears the write protection bit of group */ -#define CMD30 0x5e /* SEND_WRITE_PROT: Asks card to send state of write protection bits */ -#define CMD32 0x60 /* ERASE_WR_BLK_START_ADDR: Sets address of first block to erase */ -#define CMD33 0x61 /* ERASE_WR_BLK_END_ADDR: Sets address of last block to erase */ -#define CMD34 0x62 /* UNTAG_SECTOR: (MMC) */ -#define CMD35 0x63 /* TAG_ERASE_GROUP_START: (MMC) */ -#define CMD36 0x64 /* TAG_ERASE_GOUPR_END: (MMC) */ -#define CMD37 0x65 /* UNTAG_ERASE_GROUP: (MMC) */ -#define CMD38 0x66 /* ERASE: Erases all previously selected write blocks */ -#define CMD40 0x68 /* CRC_ON_OFF: (MMC) */ -#define CMD42 0x6a /* LOCK_UNLOCK: Used to Set/Reset the Password or lock/unlock card */ -#define CMD55 0x77 /* APP_CMD: Tells card that the next command is an application specific command */ -#define CMD56 0x78 /* GEN_CMD: Used transfer a block to or get block from card */ -#define CMD58 0x7a /* READ_OCR :Reads the OCR register of a card */ -#define CMD59 0x7b /* CRC_ON_OFF: Turns the CRC option on or off */ -#define ACMD13 0x4d /* SD_STATUS: Send the SD Status */ -#define ACMD22 0x56 /* SEND_NUM_WR_BLOCKS: Send number of the errorfree blocks */ -#define ACMD23 0x57 /* SET_WR_BLK_ERASE_COUNT: Set number blocks to erase before writing */ -#define ACMD41 0x69 /* SD_SEND_OP_COND: Sends host capacity support information */ -#define ACMD42 0x6a /* SET_CLR_CARD_DETECT: Connect/disconnect pull-up resistor on CS */ -#define ACMD51 0x73 /* SEND_SCR: Reads the SD Configuration Register (SCR) */ - -/* SPI 8-bit R1 response */ - -#define MMCSD_SPIR1_OK 0x00 /* No error bits set */ -#define MMCSD_SPIR1_IDLESTATE 0x01 /* Idle state */ -#define MMCSD_SPIR1_ERASERESET 0x02 /* Erase reset */ -#define MMCSD_SPIR1_ILLEGALCMD 0x04 /* Illegal command */ -#define MMCSD_SPIR1_CRCERROR 0x08 /* Com CRC error */ -#define MMCSD_SPIR1_ERASEERROR 0x10 /* Erase sequence error */ -#define MMCSD_SPIR1_ADDRERROR 0x20 /* Address error */ -#define MMCSD_SPIR1_PARAMERROR 0x40 /* Parameter error */ - -/* SPI 8-bit R2 response */ - -#define MMCSD_SPIR2_CARDLOCKED 0x0001 /* Card is locked */ -#define MMCSD_SPIR2_WPERASESKIP 0x0002 /* WP erase skip */ -#define MMCSD_SPIR2_LOCKFAIL 0x0002 /* Lock/unlock cmd failed */ -#define MMCSD_SPIR2_ERROR 0x0004 /* Error */ -#define MMCSD_SPIR2_CCERROR 0x0008 /* CC error */ -#define MMCSD_SPIR2_CARDECCFAIL 0x0010 /* Card ECC failed */ -#define MMCSD_SPIR2_WPVIOLATION 0x0020 /* WP violoation */ -#define MMCSD_SPIR2_ERASEPARAM 0x0040 /* Erase parameter */ -#define MMCSD_SPIR2_OUTOFRANGE 0x0080 /* Out of range */ -#define MMCSD_SPIR2_CSDOVERWRITE 0x0080 /* CSD overwrite */ -#define MMCSD_SPIR2_IDLESTATE 0x0100 /* In idle state */ -#define MMCSD_SPIR2_ERASERESET 0x0200 /* Erase reset */ -#define MMCSD_SPIR2_ILLEGALCMD 0x0400 /* Illegal command */ -#define MMCSD_SPIR2_CRCERROR 0x0800 /* Com CRC error */ -#define MMCSD_SPIR2_ERASEERROR 0x1000 /* Erase sequence error */ -#define MMCSD_SPIR2_ADDRERROR 0x2000 /* Address error */ -#define MMCSD_SPIR2_PARAMERROR 0x4000 /* Parameter error */ - -/* Last 4 bytes of the 5 byte R7 response */ - -#define MMCSD_SPIR7_VERSION_SHIFT (28) /* Bits 28-31: Command version number */ -#define MMCSD_SPIR7_VERSION_MASK ((uint32_t)0x0f << MMCSD_SPIR7_VERSION_SHIFT) -#define MMCSD_SPIR7_VOLTAGE_SHIFT (8) /* Bits 8-11: Voltage accepted */ -#define MMCSD_SPIR7_VOLTAGE_MASK ((uint32_t)0x0f << MMCSD_SPIR7_VOLTAGE_SHIFT) -#define MMCSD_SPIR7_VOLTAGE_27 ((uint32_t)0x01 << MMCSD_SPIR7_VOLTAGE_SHIFT) /* 2.7-3.6V */ -#define MMCSD_SPIR7_ECHO_SHIFT (0) /* Bits 0-7: Echoed check pattern */ -#define MMCSD_SPIR7_ECHO_MASK ((uint32_t)0xff << MMCSD_SPIR7_ECHO_SHIFT) - -/* Data Response */ - -#define MMCSD_SPIDR_MASK 0x1f /* Mask for valid data response bits */ -#define MMCSD_SPIDR_ACCEPTED 0x05 /* Data accepted */ -#define MMCSD_SPIDR_CRCERROR 0x0b /* Data rejected due to CRC error */ -#define MMCSD_SPIDR_WRERROR 0x0d /* Data rejected due to write error */ - -/* Data Tokens */ - -#define MMCSD_SPIDT_STARTBLKSNGL 0xfe /* First byte of block, single block */ -#define MMCSD_SPIDT_STARTBLKMULTI 0xfc /* First byte of block, multi-block */ -#define MMCSD_SPIDT_STOPTRANS 0xfd /* Stop transmission */ - -/* Data error token */ - -#define MMCSD_SPIDET_UPPER 0xf0 /* The upper four bits are zero */ -#define MMCSD_SPIDET_ERROR 0x01 /* Error */ -#define MMCSD_SPIDET_CCERROR 0x02 /* CC error */ -#define MMCSD_SPIDET_CARDECCFAIL 0x04 /* Card ECC failed */ -#define MMCSD_SPIDET_OUTOFRANGE 0x08 /* Out of range */ - -/* Operating Conditions register */ - -#define MMCSD_OCR_V27 ((uint32_t)1 << 15) /* Bit 15: 2.7-2.8V */ -#define MMCSD_OCR_V28 ((uint32_t)1 << 16) /* Bit 16: 2.8-2.9V */ -#define MMCSD_OCR_V29 ((uint32_t)1 << 17) /* Bit 17: 2.9-3.0V */ -#define MMCSD_OCR_V30 ((uint32_t)1 << 18) /* Bit 18: 3.0-3.1V */ -#define MMCSD_OCR_V31 ((uint32_t)1 << 19) /* Bit 19: 3.1-3.2V */ -#define MMCSD_OCR_V32 ((uint32_t)1 << 20) /* Bit 20: 3.2-3.3V */ -#define MMCSD_OCR_V33 ((uint32_t)1 << 21) /* Bit 21: 3.3-3.4V */ -#define MMCSD_OCR_V34 ((uint32_t)1 << 22) /* Bit 22: 3.4-3.5V */ -#define MMCSD_OCR_V35 ((uint32_t)1 << 23) /* Bit 23: 3.5-3.6V */ -#define MMCSD_OCR_CCS ((uint32_t)1 << 30) /* Bit 30: Card capacity status */ -#define MMCSD_OCR_BUSY ((uint32_t)1 << 31) /* Bit 31: Card powered up status bit */ - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#if defined(__cplusplus) -} -#endif -#endif /* __DRIVERS_MMCSD_MMCSD_SPI_H */ diff --git a/nuttx/drivers/mtd/Kconfig b/nuttx/drivers/mtd/Kconfig deleted file mode 100644 index ae656c474..000000000 --- a/nuttx/drivers/mtd/Kconfig +++ /dev/null @@ -1,133 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# -config MTD_AT24XX - bool "I2C-based AT24XX eeprom" - default n - select I2C - -config AT24XX_SIZE - int "at24xx size(kByte)" - default 64 - depends on MTD_AT24XX - -config AT24XX_ADDR - hex "at24xx i2c address" - default 0x50 - depends on MTD_AT24XX - -config MTD_AT45DB - bool "SPI-based AT45DB flash" - default n - select SPI - -config AT45DB_FREQUENCY - int "at45db frequency" - default 1000000 - depends on MTD_AT45DB - -config AT45DB_PREWAIT - bool "enables higher performance write logic" - default y - depends on MTD_AT45DB - -config AT45DB_PWRSAVE - bool "enables power save" - default n - depends on MTD_AT45DB - -config MTD_MP25P - bool "SPI-based M25P FLASH" - default n - select SPI - -config MP25P_SPIMODE - int "MP25P SPI mode" - default 0 - depends on MTD_MP25P - -config MP25P_MANUFACTURER - hex "MP25P manufacturers ID" - default 0x20 - depends on MTD_MP25P - ---help--- - Various manufacturers may have produced the parts. 0x20 is the manufacturer ID - for the STMicro MP25x serial FLASH. If, for example, you are using the a Macronix - International MX25 serial FLASH, the correct manufacturer ID would be 0xc2. - -config MTD_RAMTRON - bool "SPI-based RAMTRON NVRAM Devices FM25V10" - default n - select SPI - ---help--- - SPI-based RAMTRON NVRAM Devices FM25V10 - -config MTD_RAM - bool "Memory bus ram" - default n - -config MTD_SST25 - bool "SPI-based SST25 FLASH" - default n - select SPI - -config SST25_SPIMODE - int "SST25 SPI Mode" - default 0 - depends on MTD_SST25 - -config SST25_SPIFREQUENCY - int "SST25 SPI Frequency" - default 20000000 - depends on MTD_SST25 - -config SST25_READONLY - bool "SST25 Read-Only FLASH" - default n - depends on MTD_SST25 - -config SST25_SECTOR512 - bool "Simulate 512 byte Erase Blocks" - default n - depends on MTD_SST25 - -config SST25_SLOWWRITE - bool - default y - depends on MTD_SST25 - -config SST25_SLOWREAD - bool - default n - depends on MTD_SST25 - -config MTD_W25 - bool "SPI-based W25 FLASH" - default n - select SPI - -config W25_SPIMODE - int "W25 SPI Mode" - default 0 - depends on MTD_W25 - -config W25_SPIFREQUENCY - int "W25 SPI Frequency" - default 20000000 - depends on MTD_W25 - -config W25_READONLY - bool "W25 Read-Only FLASH" - default n - depends on MTD_W25 - -config W25_SECTOR512 - bool "Simulate 512 byte Erase Blocks" - default n - depends on MTD_W25 - -config W25_SLOWREAD - bool - default n - depends on MTD_W25 diff --git a/nuttx/drivers/mtd/Make.defs b/nuttx/drivers/mtd/Make.defs deleted file mode 100644 index 3102f1447..000000000 --- a/nuttx/drivers/mtd/Make.defs +++ /dev/null @@ -1,65 +0,0 @@ -############################################################################ -# drivers/mtd/Make.defs -# These driver supports various Memory Technology Devices (MTD) using the -# NuttX MTD interface. -# -# Copyright (C) 2009-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Include MTD drivers - -ifeq ($(CONFIG_MTD),y) - -CSRCS += at45db.c flash_eraseall.c ftl.c m25px.c rammtd.c ramtron.c - -ifeq ($(CONFIG_MTD_AT24XX),y) -CSRCS += at24xx.c -endif - -ifeq ($(CONFIG_MTD_SST25),y) -CSRCS += sst25.c -endif - -ifeq ($(CONFIG_MTD_W25),y) -CSRCS += w25.c -endif - -ifeq ($(CONFIG_MTD_AT25),y) -CSRCS += at25.c -endif - -# Include MTD driver support - -DEPPATH += --dep-path mtd -VPATH += :mtd - -endif diff --git a/nuttx/drivers/mtd/at24xx.c b/nuttx/drivers/mtd/at24xx.c deleted file mode 100644 index d157a9c47..000000000 --- a/nuttx/drivers/mtd/at24xx.c +++ /dev/null @@ -1,429 +0,0 @@ -/************************************************************************************ - * drivers/mtd/at24xx.c - * Driver for I2C-based at24cxx EEPROM(at24c32,at24c64,at24c128,at24c256) - * - * Copyright (C) 2011 Li Zhuoyi. All rights reserved. - * Author: Li Zhuoyi - * History: 0.1 2011-08-20 initial version - * - * 2011-11-1 Added support for larger MTD block sizes: Hal Glenn - * - * Derived from drivers/mtd/m25px.c - * - * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_MTD_AT24XX - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -/* As a minimum, the size of the AT24 part and its 7-bit I2C address are required. */ - -#ifndef CONFIG_AT24XX_SIZE -# warning "Assuming AT24 size 64" -# define CONFIG_AT24XX_SIZE 64 -#endif -#ifndef CONFIG_AT24XX_ADDR -# warning "Assuming AT24 address of 0x50" -# define CONFIG_AT24XX_ADDR 0x50 -#endif - -/* Get the part configuration based on the size configuration */ - -#if CONFIG_AT24XX_SIZE == 32 -# define AT24XX_NPAGES 128 -# define AT24XX_PAGESIZE 32 -#elif CONFIG_AT24XX_SIZE == 48 -# define AT24XX_NPAGES 192 -# define AT24XX_PAGESIZE 32 -#elif CONFIG_AT24XX_SIZE == 64 -# define AT24XX_NPAGES 256 -# define AT24XX_PAGESIZE 32 -#elif CONFIG_AT24XX_SIZE == 128 -# define AT24XX_NPAGES 256 -# define AT24XX_PAGESIZE 64 -#elif CONFIG_AT24XX_SIZE == 256 -# define AT24XX_NPAGES 512 -# define AT24XX_PAGESIZE 64 -#endif - -/* For applications where a file system is used on the AT24, the tiny page sizes - * will result in very inefficient FLASH usage. In such cases, it is better if - * blocks are comprised of "clusters" of pages so that the file system block - * size is, say, 256 or 512 bytes. In any event, the block size *must* be an - * even multiple of the pages. - */ - -#ifndef CONFIG_AT24XX_MTD_BLOCKSIZE -# warning "Assuming driver block size is the same as the FLASH page size" -# define CONFIG_AT24XX_MTD_BLOCKSIZE AT24XX_PAGESIZE -#endif - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s - * must appear at the beginning of the definition so that you can freely - * cast between pointers to struct mtd_dev_s and struct at24c_dev_s. - */ - -struct at24c_dev_s -{ - struct mtd_dev_s mtd; /* MTD interface */ - FAR struct i2c_dev_s *dev; /* Saved I2C interface instance */ - uint8_t addr; /* I2C address */ - uint16_t pagesize; /* 32, 63 */ - uint16_t npages; /* 128, 256, 512, 1024 */ -}; - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/* MTD driver methods */ - -static int at24c_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t at24c_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buf); -static ssize_t at24c_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); -static ssize_t at24c_read(FAR struct mtd_dev_s *dev, off_t offset, - size_t nbytes,FAR uint8_t *buffer); -static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/* At present, only a signal AT24 part is supported. In this case, a statically - * allocated state structure may be used. - */ - -static struct at24c_dev_s g_at24c; - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -static int at24c_eraseall(FAR struct at24c_dev_s *priv) -{ - int startblock = 0; - uint8_t buf[AT24XX_PAGESIZE + 2]; - - memset(&buf[2],0xff,priv->pagesize); - I2C_SETADDRESS(priv->dev,priv->addr,7); - I2C_SETFREQUENCY(priv->dev,100000); - - for (startblock = 0; startblock < priv->npages; startblock++) - { - uint16_t offset = startblock * priv->pagesize; - buf[1] = offset & 0xff; - buf[0] = (offset >> 8) & 0xff; - - while (I2C_WRITE(priv->dev, buf, 2) < 0) - { - usleep(1000); - } - I2C_WRITE(priv->dev, buf, priv->pagesize + 2); - } - - return OK; -} - -/************************************************************************************ - * Name: at24c_erase - ************************************************************************************/ - -static int at24c_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ - /* EEprom need not erase */ - - return (int)nblocks; -} - -/************************************************************************************ - * Name: at24c_bread - ************************************************************************************/ - -static ssize_t at24c_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buffer) -{ - FAR struct at24c_dev_s *priv = (FAR struct at24c_dev_s *)dev; - size_t blocksleft; - -#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE - startblock *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE); - nblocks *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE); -#endif - blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - if (startblock >= priv->npages) - { - return 0; - } - - if (startblock + nblocks > priv->npages) - { - nblocks = priv->npages - startblock; - } - - I2C_SETADDRESS(priv->dev,priv->addr,7); - I2C_SETFREQUENCY(priv->dev,100000); - - while (blocksleft-- > 0) - { - uint16_t offset = startblock * priv->pagesize; - uint8_t buf[2]; - buf[1] = offset & 0xff; - buf[0] = (offset >> 8) & 0xff; - - while (I2C_WRITE(priv->dev, buf, 2) < 0) - { - fvdbg("wait\n"); - usleep(1000); - } - - I2C_READ(priv->dev, buffer, priv->pagesize); - startblock++; - buffer += priv->pagesize; - } - -#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE - return nblocks / (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE); -#else - return nblocks; -#endif -} - -/************************************************************************************ - * Name: at24c_bwrite - * - * Operates on MTD block's and translates to FLASH pages - * - ************************************************************************************/ - -static ssize_t at24c_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) -{ - FAR struct at24c_dev_s *priv = (FAR struct at24c_dev_s *)dev; - size_t blocksleft; - uint8_t buf[AT24XX_PAGESIZE+2]; - -#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE - startblock *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE); - nblocks *= (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE); -#endif - blocksleft = nblocks; - - if (startblock >= priv->npages) - { - return 0; - } - - if (startblock + nblocks > priv->npages) - { - nblocks = priv->npages - startblock; - } - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - I2C_SETADDRESS(priv->dev, priv->addr, 7); - I2C_SETFREQUENCY(priv->dev, 100000); - - while (blocksleft-- > 0) - { - uint16_t offset = startblock * priv->pagesize; - while (I2C_WRITE(priv->dev, (uint8_t *)&offset, 2) < 0) - { - fvdbg("wait\n"); - usleep(1000); - } - - buf[1] = offset & 0xff; - buf[0] = (offset >> 8) & 0xff; - memcpy(&buf[2], buffer, priv->pagesize); - - I2C_WRITE(priv->dev, buf, priv->pagesize + 2); - startblock++; - buffer += priv->pagesize; - } - -#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE - return nblocks / (CONFIG_AT24XX_MTD_BLOCKSIZE / AT24XX_PAGESIZE); -#else - return nblocks; -#endif -} - -/************************************************************************************ - * Name: at24c_ioctl - ************************************************************************************/ - -static int at24c_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct at24c_dev_s *priv = (FAR struct at24c_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - fvdbg("cmd: %d \n", cmd); - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - * - * blocksize: - * May be user defined. The block size for the at24XX devices may be - * larger than the page size in order to better support file systems. - * The read and write functions translate BLOCKS to pages for the - * small flash devices - * erasesize: - * It has to be at least as big as the blocksize, bigger serves no - * purpose. - * neraseblocks - * Note that the device size is in kilobits and must be scaled by - * 1024 / 8 - */ - -#if CONFIG_AT24XX_MTD_BLOCKSIZE > AT24XX_PAGESIZE - geo->blocksize = CONFIG_AT24XX_MTD_BLOCKSIZE; - geo->erasesize = CONFIG_AT24XX_MTD_BLOCKSIZE; - geo->neraseblocks = (CONFIG_AT24XX_SIZE * 1024 / 8) / CONFIG_AT24XX_MTD_BLOCKSIZE; -#else - geo->blocksize = priv->pagesize; - geo->erasesize = priv->pagesize; - geo->neraseblocks = priv->npages; -#endif - ret = OK; - - fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); - } - } - break; - - case MTDIOC_BULKERASE: - ret=at24c_eraseall(priv); - break; - - case MTDIOC_XIPBASE: - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: at24c_initialize - * - * Description: - * Create an initialize MTD device instance. MTD devices are not registered - * in the file system, but are created as instances that can be bound to - * other functions (such as a block or character driver front end). - * - ************************************************************************************/ - -FAR struct mtd_dev_s *at24c_initialize(FAR struct i2c_dev_s *dev) -{ - FAR struct at24c_dev_s *priv; - - fvdbg("dev: %p\n", dev); - - /* Allocate a state structure (we allocate the structure instead of using - * a fixed, static allocation so that we can handle multiple FLASH devices. - * The current implementation would handle only one FLASH part per I2C - * device (only because of the SPIDEV_FLASH definition) and so would have - * to be extended to handle multiple FLASH parts on the same I2C bus. - */ - - priv = &g_at24c; - if (priv) - { - /* Initialize the allocated structure */ - - priv->addr = CONFIG_AT24XX_ADDR; - priv->pagesize = AT24XX_PAGESIZE; - priv->npages = AT24XX_NPAGES; - - priv->mtd.erase = at24c_erase; - priv->mtd.bread = at24c_bread; - priv->mtd.bwrite = at24c_bwrite; - priv->mtd.ioctl = at24c_ioctl; - priv->dev = dev; - } - - /* Return the implementation-specific state structure as the MTD device */ - - fvdbg("Return %p\n", priv); - return (FAR struct mtd_dev_s *)priv; -} - -#endif diff --git a/nuttx/drivers/mtd/at25.c b/nuttx/drivers/mtd/at25.c deleted file mode 100644 index c58b16122..000000000 --- a/nuttx/drivers/mtd/at25.c +++ /dev/null @@ -1,710 +0,0 @@ -/************************************************************************************ - * drivers/mtd/at25.c - * Driver for SPI-based AT25DF321 (32Mbit) flash. - * - * Copyright (C) 2009-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * Petteri Aimonen - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -#ifndef CONFIG_AT25_SPIMODE -# define CONFIG_AT25_SPIMODE SPIDEV_MODE0 -#endif - -/* AT25 Registers *******************************************************************/ -/* Indentification register values */ - -#define AT25_MANUFACTURER 0x1F -#define AT25_AT25DF321_TYPE 0x47 /* 32 M-bit */ - -/* AT25DF321 capacity is 4,194,304 bytes: - * (64 sectors) * (65,536 bytes per sector) - * (16384 pages) * (256 bytes per page) - */ - -#define AT25_AT25DF321_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4096 */ -#define AT25_AT25DF321_NSECTORS 1024 -#define AT25_AT25DF321_PAGE_SHIFT 9 /* Page size 1 << 9 = 512 */ -#define AT25_AT25DF321_NPAGES 8192 - -/* Instructions */ -/* Command Value N Description Addr Dummy Data */ -#define AT25_WREN 0x06 /* 1 Write Enable 0 0 0 */ -#define AT25_WRDI 0x04 /* 1 Write Disable 0 0 0 */ -#define AT25_RDID 0x9f /* 1 Read Identification 0 0 1-3 */ -#define AT25_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */ -#define AT25_WRSR 0x01 /* 1 Write Status Register 0 0 1 */ -#define AT25_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */ -#define AT25_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */ -#define AT25_PP 0x02 /* 1 Page Program 3 0 1-256 */ -#define AT25_SE 0x20 /* 1 Sector Erase 3 0 0 */ -#define AT25_BE 0xc7 /* 1 Bulk Erase 0 0 0 */ -#define AT25_DP 0xb9 /* 2 Deep power down 0 0 0 */ -#define AT25_RES 0xab /* 2 Read Electronic Signature 0 3 >=1 */ - -/* Status register bit definitions */ - -#define AT25_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */ -#define AT25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */ -#define AT25_SR_EPE (1 << 5) /* Bit 5: Erase/program error */ -#define AT25_SR_UNPROT 0x00 /* Global unprotect command */ - -#define AT25_DUMMY 0xa5 - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s - * must appear at the beginning of the definition so that you can freely - * cast between pointers to struct mtd_dev_s and struct at25_dev_s. - */ - -struct at25_dev_s -{ - struct mtd_dev_s mtd; /* MTD interface */ - FAR struct spi_dev_s *dev; /* Saved SPI interface instance */ - uint8_t sectorshift; /* 16 or 18 */ - uint8_t pageshift; /* 8 */ - uint16_t nsectors; /* 128 or 64 */ - uint32_t npages; /* 32,768 or 65,536 */ -}; - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/* Helpers */ - -static void at25_lock(FAR struct spi_dev_s *dev); -static inline void at25_unlock(FAR struct spi_dev_s *dev); -static inline int at25_readid(struct at25_dev_s *priv); -static void at25_waitwritecomplete(struct at25_dev_s *priv); -static void at25_writeenable(struct at25_dev_s *priv); -static inline void at25_sectorerase(struct at25_dev_s *priv, off_t offset); -static inline int at25_bulkerase(struct at25_dev_s *priv); -static inline void at25_pagewrite(struct at25_dev_s *priv, FAR const uint8_t *buffer, - off_t offset); - -/* MTD driver methods */ - -static int at25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t at25_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buf); -static ssize_t at25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); -static ssize_t at25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int at25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: at25_lock - ************************************************************************************/ - -static void at25_lock(FAR struct spi_dev_s *dev) -{ - /* On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of - * transfers. The bus should be locked before the chip is selected. - * - * This is a blocking call and will not return until we have exclusiv access to - * the SPI buss. We will retain that exclusive access until the bus is unlocked. - */ - - (void)SPI_LOCK(dev, true); - - /* After locking the SPI bus, the we also need call the setfrequency, setbits, and - * setmode methods to make sure that the SPI is properly configured for the device. - * If the SPI buss is being shared, then it may have been left in an incompatible - * state. - */ - - SPI_SETMODE(dev, CONFIG_AT25_SPIMODE); - SPI_SETBITS(dev, 8); - (void)SPI_SETFREQUENCY(dev, 20000000); -} - -/************************************************************************************ - * Name: at25_unlock - ************************************************************************************/ - -static inline void at25_unlock(FAR struct spi_dev_s *dev) -{ - (void)SPI_LOCK(dev, false); -} - -/************************************************************************************ - * Name: at25_readid - ************************************************************************************/ - -static inline int at25_readid(struct at25_dev_s *priv) -{ - uint16_t manufacturer; - uint16_t memory; - uint16_t version; - - fvdbg("priv: %p\n", priv); - - /* Lock the SPI bus, configure the bus, and select this FLASH part. */ - - at25_lock(priv->dev); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Read ID (RDID)" command and read the first three ID bytes */ - - (void)SPI_SEND(priv->dev, AT25_RDID); - manufacturer = SPI_SEND(priv->dev, AT25_DUMMY); - memory = SPI_SEND(priv->dev, AT25_DUMMY); - - /* Deselect the FLASH and unlock the bus */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - at25_unlock(priv->dev); - - fvdbg("manufacturer: %02x memory: %02x\n", - manufacturer, memory); - - /* Check for a valid manufacturer and memory type */ - - if (manufacturer == AT25_MANUFACTURER && memory == AT25_AT25DF321_TYPE) - { - priv->sectorshift = AT25_AT25DF321_SECTOR_SHIFT; - priv->nsectors = AT25_AT25DF321_NSECTORS; - priv->pageshift = AT25_AT25DF321_PAGE_SHIFT; - priv->npages = AT25_AT25DF321_NPAGES; - return OK; - } - - return -ENODEV; -} - -/************************************************************************************ - * Name: at25_waitwritecomplete - ************************************************************************************/ - -static void at25_waitwritecomplete(struct at25_dev_s *priv) -{ - uint8_t status; - - /* Are we the only device on the bus? */ - -#ifdef CONFIG_SPI_OWNBUS - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->dev, AT25_RDSR); - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->dev, AT25_DUMMY); - } - while ((status & AT25_SR_WIP) != 0); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - -#else - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->dev, AT25_RDSR); - - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->dev, AT25_DUMMY); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - - /* Given that writing could take up to few tens of milliseconds, and erasing - * could take more. The following short delay in the "busy" case will allow - * other peripherals to access the SPI bus. - */ - - if ((status & AT25_SR_WIP) != 0) - { - at25_unlock(priv->dev); - usleep(10000); - at25_lock(priv->dev); - } - } - while ((status & AT25_SR_WIP) != 0); -#endif - - if (status & AT25_SR_EPE) - { - fdbg("Write error, status: 0x%02x\n", status); - } - - fvdbg("Complete, status: 0x%02x\n", status); -} - -/************************************************************************************ - * Name: at25_writeenable - ************************************************************************************/ - -static void at25_writeenable(struct at25_dev_s *priv) -{ - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - (void)SPI_SEND(priv->dev, AT25_WREN); - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Enabled\n"); -} - -/************************************************************************************ - * Name: at25_sectorerase - ************************************************************************************/ - -static inline void at25_sectorerase(struct at25_dev_s *priv, off_t sector) -{ - off_t offset = sector << priv->sectorshift; - - fvdbg("sector: %08lx\n", (long)sector); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - at25_waitwritecomplete(priv); - - /* Send write enable instruction */ - - at25_writeenable(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Sector Erase (SE)" instruction */ - - (void)SPI_SEND(priv->dev, AT25_SE); - - /* Send the sector offset high byte first. For all of the supported - * parts, the sector number is completely contained in the first byte - * and the values used in the following two bytes don't really matter. - */ - - (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); - (void)SPI_SEND(priv->dev, offset & 0xff); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Erased\n"); -} - -/************************************************************************************ - * Name: at25_bulkerase - ************************************************************************************/ - -static inline int at25_bulkerase(struct at25_dev_s *priv) -{ - fvdbg("priv: %p\n", priv); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - at25_waitwritecomplete(priv); - - /* Send write enable instruction */ - - at25_writeenable(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Bulk Erase (BE)" instruction */ - - (void)SPI_SEND(priv->dev, AT25_BE); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Return: OK\n"); - return OK; -} - -/************************************************************************************ - * Name: at25_pagewrite - ************************************************************************************/ - -static inline void at25_pagewrite(struct at25_dev_s *priv, FAR const uint8_t *buffer, - off_t page) -{ - off_t offset = page << 8; - - fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - at25_waitwritecomplete(priv); - - /* Enable the write access to the FLASH */ - - at25_writeenable(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Page Program (PP)" command */ - - (void)SPI_SEND(priv->dev, AT25_PP); - - /* Send the page offset high byte first. */ - - (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); - (void)SPI_SEND(priv->dev, offset & 0xff); - - /* Then write the specified number of bytes */ - - SPI_SNDBLOCK(priv->dev, buffer, 256); - - /* Deselect the FLASH: Chip Select high */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Written\n"); -} - -/************************************************************************************ - * Name: at25_erase - ************************************************************************************/ - -static int at25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ - FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev; - size_t blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock access to the SPI bus until we complete the erase */ - - at25_lock(priv->dev); - while (blocksleft-- > 0) - { - /* Erase each sector */ - - at25_sectorerase(priv, startblock); - startblock++; - } - - at25_unlock(priv->dev); - return (int)nblocks; -} - -/************************************************************************************ - * Name: at25_bread - ************************************************************************************/ - -static ssize_t at25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buffer) -{ - FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev; - ssize_t nbytes; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* On this device, we can handle the block read just like the byte-oriented read */ - - nbytes = at25_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer); - if (nbytes > 0) - { - return nbytes >> priv->pageshift; - } - - return (int)nbytes; -} - -/************************************************************************************ - * Name: at25_bwrite - ************************************************************************************/ - -static ssize_t at25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) -{ - FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev; - size_t blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock the SPI bus and write each page to FLASH */ - - at25_lock(priv->dev); - while (blocksleft-- > 0) - { - at25_pagewrite(priv, buffer, startblock * 2); - at25_pagewrite(priv, buffer + 256, startblock * 2 + 1); - buffer += 1 << priv->pageshift; - startblock++; - } - - at25_unlock(priv->dev); - return nblocks; -} - -/************************************************************************************ - * Name: at25_read - ************************************************************************************/ - -static ssize_t at25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer) -{ - FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev; - - fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - at25_waitwritecomplete(priv); - - /* Lock the SPI bus and select this FLASH part */ - - at25_lock(priv->dev); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read from Memory " instruction */ - - (void)SPI_SEND(priv->dev, AT25_READ); - - /* Send the page offset high byte first. */ - - (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); - (void)SPI_SEND(priv->dev, offset & 0xff); - - /* Then read all of the requested bytes */ - - SPI_RECVBLOCK(priv->dev, buffer, nbytes); - - /* Deselect the FLASH and unlock the SPI bus */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - at25_unlock(priv->dev); - - fvdbg("return nbytes: %d\n", (int)nbytes); - return nbytes; -} - -/************************************************************************************ - * Name: at25_ioctl - ************************************************************************************/ - -static int at25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct at25_dev_s *priv = (FAR struct at25_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - fvdbg("cmd: %d \n", cmd); - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - */ - - geo->blocksize = (1 << priv->pageshift); - geo->erasesize = (1 << priv->sectorshift); - geo->neraseblocks = priv->nsectors; - ret = OK; - - fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); - } - } - break; - - case MTDIOC_BULKERASE: - { - /* Erase the entire device */ - - at25_lock(priv->dev); - ret = at25_bulkerase(priv); - at25_unlock(priv->dev); - } - break; - - case MTDIOC_XIPBASE: - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - fvdbg("return %d\n", ret); - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: at25_initialize - * - * Description: - * Create an initialize MTD device instance. MTD devices are not registered - * in the file system, but are created as instances that can be bound to - * other functions (such as a block or character driver front end). - * - ************************************************************************************/ - -FAR struct mtd_dev_s *at25_initialize(FAR struct spi_dev_s *dev) -{ - FAR struct at25_dev_s *priv; - int ret; - - fvdbg("dev: %p\n", dev); - - /* Allocate a state structure (we allocate the structure instead of using - * a fixed, static allocation so that we can handle multiple FLASH devices. - * The current implementation would handle only one FLASH part per SPI - * device (only because of the SPIDEV_FLASH definition) and so would have - * to be extended to handle multiple FLASH parts on the same SPI bus. - */ - - priv = (FAR struct at25_dev_s *)kmalloc(sizeof(struct at25_dev_s)); - if (priv) - { - /* Initialize the allocated structure */ - - priv->mtd.erase = at25_erase; - priv->mtd.bread = at25_bread; - priv->mtd.bwrite = at25_bwrite; - priv->mtd.read = at25_read; - priv->mtd.ioctl = at25_ioctl; - priv->dev = dev; - - /* Deselect the FLASH */ - - SPI_SELECT(dev, SPIDEV_FLASH, false); - - /* Identify the FLASH chip and get its capacity */ - - ret = at25_readid(priv); - if (ret != OK) - { - /* Unrecognized! Discard all of that work we just did and return NULL */ - - fdbg("Unrecognized\n"); - kfree(priv); - priv = NULL; - } - else - { - /* Unprotect all sectors */ - - at25_writeenable(priv); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - (void)SPI_SEND(priv->dev, AT25_WRSR); - (void)SPI_SEND(priv->dev, AT25_SR_UNPROT); - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - } - } - - /* Return the implementation-specific state structure as the MTD device */ - - fvdbg("Return %p\n", priv); - return (FAR struct mtd_dev_s *)priv; -} diff --git a/nuttx/drivers/mtd/at45db.c b/nuttx/drivers/mtd/at45db.c deleted file mode 100644 index f3c0c72c1..000000000 --- a/nuttx/drivers/mtd/at45db.c +++ /dev/null @@ -1,899 +0,0 @@ -/************************************************************************************ - * drivers/mtd/at45db.c - * Driver for SPI-based AT45DB161D (16Mbit) - * - * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/* Ordering Code Detail: - * - * AT 45DB 16 1 D – SS U - * | | | | | | `- Device grade - * | | | | | `- Package Option - * | | | | `- Device revision - * | | | `- Interface: 1=serial - * | | `- Capacity: 16=16Mbit - * | `- Product family - * `- Atmel designator - */ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -/* Configuration ********************************************************************/ -/* CONFIG_AT45DB_PREWAIT enables higher performance write logic: We leave the chip - * busy after write and erase operations. This improves write and erase performance - * because we do not have to wait as long between transactions (other processing can - * occur while the chip is busy) but means that the chip must stay powered: - */ - -#if defined(CONFIG_AT45DB_PWRSAVE) && defined(CONFIG_AT45DB_PREWAIT) -# error "Both CONFIG_AT45DB_PWRSAVE and CONFIG_AT45DB_PREWAIT are defined" -#endif - -/* If the user has provided no frequency, use 1MHz */ - -#ifndef CONFIG_AT45DB_FREQUENCY -# define CONFIG_AT45DB_FREQUENCY 1000000 -#endif - -/* SPI Commands *********************************************************************/ - -/* Read commands */ - -#define AT45DB_RDMN 0xd2 /* Main Memory Page Read */ -#define AT45DB_RDARRY 0xe8 /* Continuous Array Read (Legacy Command) */ -#define AT45DB_RDARRAYLF 0x03 /* Continuous Array Read (Low Frequency) */ -#define AT45DB_RDARRAYHF 0x0b /* Continuous Array Read (High Frequency) */ -#define AT45DB_RDBF1LF 0xd1 /* Buffer 1 Read (Low Frequency) */ -#define AT45DB_RDBF2LF 0xd3 /* Buffer 2 Read (Low Frequency) */ -#define AT45DB_RDBF1 0xd4 /* Buffer 1 Read */ -#define AT45DB_RDBF2 0xd6 /* Buffer 2 Read */ - -/* Program and Erase Commands */ - -#define AT45DB_WRBF1 0x84 /* Buffer 1 Write */ -#define AT45DB_WRBF2 0x87 /* Buffer 2 Write */ -#define AT45DB_BF1TOMNE 0x83 /* Buffer 1 to Main Memory Page Program with Built-in Erase */ -#define AT45DB_BF2TOMNE 0x86 /* Buffer 2 to Main Memory Page Program with Built-in Erase */ -#define AT45DB_BF1TOMN 0x88 /* Buffer 1 to Main Memory Page Program without Built-in Erase */ -#define AT45DB_BF2TOMN 0x89 /* Buffer 2 to Main Memory Page Program without Built-in Erase */ -#define AT45DB_PGERASE 0x81 /* Page Erase */ -#define AT45DB_BLKERASE 0x50 /* Block Erase */ -#define AT45DB_SECTERASE 0x7c /* Sector Erase */ -#define AT45DB_CHIPERASE1 0xc7 /* Chip Erase - byte 1 */ -# define AT45DB_CHIPERASE2 0x94 /* Chip Erase - byte 2 */ -# define AT45DB_CHIPERASE3 0x80 /* Chip Erase - byte 3 */ -# define AT45DB_CHIPERASE4 0x9a /* Chip Erase - byte 4 */ -#define AT45DB_MNTHRUBF1 0x82 /* Main Memory Page Program Through Buffer 1 */ -#define AT45DB_MNTHRUBF2 0x85 /* Main Memory Page Program Through Buffer 2 */ - -/* Protection and Security Commands */ - -#define AT45DB_ENABPROT1 0x3d /* Enable Sector Protection - byte 1 */ -# define AT45DB_ENABPROT2 0x2a /* Enable Sector Protection - byte 2 */ -# define AT45DB_ENABPROT3 0x7f /* Enable Sector Protection - byte 3 */ -# define AT45DB_ENABPROT4 0xa9 /* Enable Sector Protection - byte 4 */ -#define AT45DB_DISABPROT1 0x3d /* Disable Sector Protection - byte 1 */ -# define AT45DB_DISABPROT2 0x2a /* Disable Sector Protection - byte 2 */ -# define AT45DB_DISABPROT3 0x7f /* Disable Sector Protection - byte 3 */ -# define AT45DB_DISABPROT4 0x9a /* Disable Sector Protection - byte 4 */ -#define AT45DB_ERASEPROT1 0x3d /* Erase Sector Protection Register - byte 1 */ -# define AT45DB_ERASEPROT2 0x2a /* Erase Sector Protection Register - byte 2 */ -# define AT45DB_ERASEPROT3 0x7f /* Erase Sector Protection Register - byte 3 */ -# define AT45DB_ERASEPROT4 0xcf /* Erase Sector Protection Register - byte 4 */ -#define AT45DB_PROGPROT1 0x3d /* Program Sector Protection Register - byte 1 */ -# define AT45DB_PROGPROT2 0x2a /* Program Sector Protection Register - byte 2 */ -# define AT45DB_PROGPROT3 0x7f /* Program Sector Protection Register - byte 3 */ -# define AT45DB_PROGPROT4 0xfc /* Program Sector Protection Register - byte 4 */ -#define AT45DB_RDPROT 0x32 /* Read Sector Protection Register */ -#define AT45DB_LOCKDOWN1 0x3d /* Sector Lockdown - byte 1 */ -# define AT45DB_LOCKDOWN2 0x2a /* Sector Lockdown - byte 2 */ -# define AT45DB_LOCKDOWN3 0x7f /* Sector Lockdown - byte 3 */ -# define AT45DB_LOCKDOWN4 0x30 /* Sector Lockdown - byte 4 */ -#define AT45DB_RDLOCKDOWN 0x35 /* Read Sector Lockdown Register */ -#define AT45DB_PROGSEC1 0x9b /* Program Security Register - byte 1 */ -# define AT45DB_PROGSEC2 0x00 /* Program Security Register - byte 2 */ -# define AT45DB_PROGSEC3 0x00 /* Program Security Register - byte 3 */ -# define AT45DB_PROGSEC4 0x00 /* Program Security Register - byte 4 */ -#define AT45DB_RDSEC 0x77 /* Read Security Register */ - -/* Additional commands */ - -#define AT45DB_MNTOBF1XFR 0x53 /* Main Memory Page to Buffer 1 Transfer */ -#define AT45DB_MNTOBF2XFR 0x55 /* Main Memory Page to Buffer 2 Transfer */ -#define AT45DB_MNBF1CMP 0x60 /* Main Memory Page to Buffer 1 Compare */ -#define AT45DB_MNBF2CMP 0x61 /* Main Memory Page to Buffer 2 Compare */ -#define AT45DB_AUTOWRBF1 0x58 /* Auto Page Rewrite through Buffer 1 */ -#define AT45DB_AUTOWRBF2 0x59 /* Auto Page Rewrite through Buffer 2 */ -#define AT45DB_PWRDOWN 0xb9 /* Deep Power-down */ -#define AT45DB_RESUME 0xab /* Resume from Deep Power-down */ -#define AT45DB_RDSR 0xd7 /* Status Register Read */ -#define AT45DB_RDDEVID 0x9f /* Manufacturer and Device ID Read */ - -#define AT45DB_MANUFACTURER 0x1f /* Manufacturer ID: Atmel */ -#define AT45DB_DEVID1_CAPMSK 0x1f /* Bits 0-4: Capacity */ -#define AT45DB_DEVID1_1MBIT 0x02 /* xxx0 0010 = 1Mbit AT45DB011 */ -#define AT45DB_DEVID1_2MBIT 0x03 /* xxx0 0012 = 2Mbit AT45DB021 */ -#define AT45DB_DEVID1_4MBIT 0x04 /* xxx0 0100 = 4Mbit AT45DB041 */ -#define AT45DB_DEVID1_8MBIT 0x05 /* xxx0 0101 = 8Mbit AT45DB081 */ -#define AT45DB_DEVID1_16MBIT 0x06 /* xxx0 0110 = 16Mbit AT45DB161 */ -#define AT45DB_DEVID1_32MBIT 0x07 /* xxx0 0111 = 32Mbit AT45DB321 */ -#define AT45DB_DEVID1_64MBIT 0x08 /* xxx0 1000 = 32Mbit AT45DB641 */ -#define AT45DB_DEVID1_FAMMSK 0xe0 /* Bits 5-7: Family */ -#define AT45DB_DEVID1_DFLASH 0x20 /* 001x xxxx = Dataflash */ -#define AT45DB_DEVID1_AT26DF 0x40 /* 010x xxxx = AT26DFxxx series (Not supported) */ -#define AT45DB_DEVID2_VERMSK 0x1f /* Bits 0-4: MLC mask */ -#define AT45DB_DEVID2_MLCMSK 0xe0 /* Bits 5-7: MLC mask */ - -/* Status register bit definitions */ - -#define AT45DB_SR_RDY (1 << 7) /* Bit 7: RDY/ Not BUSY */ -#define AT45DB_SR_COMP (1 << 6) /* Bit 6: COMP */ -#define AT45DB_SR_PROTECT (1 << 1) /* Bit 1: PROTECT */ -#define AT45DB_SR_PGSIZE (1 << 0) /* Bit 0: PAGE_SIZE */ - -/* 1 Block = 16 pages; 1 sector = 256 pages */ - -#define PG_PER_BLOCK (16) -#define PG_PER_SECTOR (256) - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s - * must appear at the beginning of the definition so that you can freely - * cast between pointers to struct mtd_dev_s and struct at45db_dev_s. - */ - -struct at45db_dev_s -{ - struct mtd_dev_s mtd; /* MTD interface */ - FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ - uint8_t pageshift; /* log2 of the page size (eg. 1 << 9 = 512) */ - uint32_t npages; /* Number of pages in the device */ -}; - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/* Lock and per-transaction configuration */ - -static void at45db_lock(struct at45db_dev_s *priv); -static inline void at45db_unlock(struct at45db_dev_s *priv); - -/* Power management */ - -#ifdef CONFIG_AT45DB_PWRSAVE -static void at45db_pwrdown(struct at45db_dev_s *priv); -static void at45db_resume(struct at45db_dev_s *priv); -#else -# define at45db_pwrdown(priv) -# define at45db_resume(priv) -#endif - -/* Low-level AT45DB Helpers */ - -static inline int at45db_rdid(struct at45db_dev_s *priv); -static inline uint8_t at45db_rdsr(struct at45db_dev_s *priv); -static uint8_t at45db_waitbusy(struct at45db_dev_s *priv); -static inline void at45db_pgerase(struct at45db_dev_s *priv, off_t offset); -static inline int at32db_chiperase(struct at45db_dev_s *priv); -static inline void at45db_pgwrite(struct at45db_dev_s *priv, FAR const uint8_t *buffer, - off_t offset); - -/* MTD driver methods */ - -static int at45db_erase(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks); -static ssize_t at45db_bread(FAR struct mtd_dev_s *mtd, off_t startblock, - size_t nblocks, FAR uint8_t *buf); -static ssize_t at45db_bwrite(FAR struct mtd_dev_s *mtd, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); -static ssize_t at45db_read(FAR struct mtd_dev_s *mtd, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int at45db_ioctl(FAR struct mtd_dev_s *mtd, int cmd, unsigned long arg); - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/* Chip erase sequence */ - -#define CHIP_ERASE_SIZE 4 -static const uint8_t g_chiperase[CHIP_ERASE_SIZE] = {0xc7, 0x94, 0x80, 0x9a}; - -/* Sequence to program the device to binary page sizes{256, 512, 1024} */ - -#define BINPGSIZE_SIZE 4 -static const uint8_t g_binpgsize[BINPGSIZE_SIZE] = {0x3d, 0x2a, 0x80, 0xa6}; - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: at45db_lock - ************************************************************************************/ - -static void at45db_lock(struct at45db_dev_s *priv) -{ - /* On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of - * transfers. The bus should be locked before the chip is selected. - * - * This is a blocking call and will not return until we have exclusiv access to - * the SPI buss. We will retain that exclusive access until the bus is unlocked. - */ - - (void)SPI_LOCK(priv->spi, true); - - /* After locking the SPI bus, the we also need call the setfrequency, setbits, and - * setmode methods to make sure that the SPI is properly configured for the device. - * If the SPI buss is being shared, then it may have been left in an incompatible - * state. - */ - - SPI_SETMODE(priv->spi, SPIDEV_MODE0); - SPI_SETBITS(priv->spi, 8); - (void)SPI_SETFREQUENCY(priv->spi, CONFIG_AT45DB_FREQUENCY); -} - -/************************************************************************************ - * Name: at45db_unlock - ************************************************************************************/ - -static inline void at45db_unlock(struct at45db_dev_s *priv) -{ - (void)SPI_LOCK(priv->spi, false); -} - -/************************************************************************************ - * Name: at45db_pwrdown - ************************************************************************************/ - -#ifdef CONFIG_AT45DB_PWRSAVE -static void at45db_pwrdown(struct at45db_dev_s *priv) -{ - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SEND(priv->spi, AT45DB_PWRDOWN); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); -} -#endif - -/************************************************************************************ - * Name: at45db_resume - ************************************************************************************/ - -#ifdef CONFIG_AT45DB_PWRSAVE -static void at45db_resume(struct at45db_dev_s *priv) -{ - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SEND(priv->spi, AT45DB_RESUME); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - up_udelay(50); -} -#endif - -/************************************************************************************ - * Name: at45db_rdid - ************************************************************************************/ - -static inline int at45db_rdid(struct at45db_dev_s *priv) -{ - uint8_t capacity; - uint8_t devid[3]; - - fvdbg("priv: %p\n", priv); - - /* Configure the bus, and select this FLASH part. (The caller should alread have - * loced the bus for exclusive access) - */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send the " Manufacturer and Device ID Read" command and read the next three - * ID bytes from the FLASH. - */ - - (void)SPI_SEND(priv->spi, AT45DB_RDDEVID); - SPI_RECVBLOCK(priv->spi, devid, 3); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - - fvdbg("manufacturer: %02x devid1: %02x devid2: %02x\n", - devid[0], devid[1], devid[2]); - - /* Check for a valid manufacturer and memory family */ - - if (devid[0] == AT45DB_MANUFACTURER && - (devid[1] & AT45DB_DEVID1_FAMMSK) == AT45DB_DEVID1_DFLASH) - { - /* Okay.. is it a FLASH capacity that we understand? */ - - capacity = devid[1] & AT45DB_DEVID1_CAPMSK; - switch (capacity) - { - case AT45DB_DEVID1_1MBIT: - /* Save the FLASH geometry for the 16Mbit AT45DB011 */ - - priv->pageshift = 8; /* Page size = 256 bytes */ - priv->npages = 512; /* 512 pages */ - return OK; - - case AT45DB_DEVID1_2MBIT: - /* Save the FLASH geometry for the 16Mbit AT45DB021 */ - - priv->pageshift = 8; /* Page size = 256/264 bytes */ - priv->npages = 1024; /* 1024 pages */ - return OK; - - case AT45DB_DEVID1_4MBIT: - /* Save the FLASH geometry for the 16Mbit AT45DB041 */ - - priv->pageshift = 8; /* Page size = 256/264 bytes */ - priv->npages = 2048; /* 2048 pages */ - return OK; - - case AT45DB_DEVID1_8MBIT: - /* Save the FLASH geometry for the 16Mbit AT45DB081 */ - - priv->pageshift = 8; /* Page size = 256/264 bytes */ - priv->npages = 4096; /* 4096 pages */ - return OK; - - case AT45DB_DEVID1_16MBIT: - /* Save the FLASH geometry for the 16Mbit AT45DB161 */ - - priv->pageshift = 9; /* Page size = 512/528 bytes */ - priv->npages = 4096; /* 4096 pages */ - return OK; - - case AT45DB_DEVID1_32MBIT: - /* Save the FLASH geometry for the 16Mbit AT45DB321 */ - - priv->pageshift = 9; /* Page size = 512/528 bytes */ - priv->npages = 8192; /* 8192 pages */ - return OK; - - case AT45DB_DEVID1_64MBIT: - /* Save the FLASH geometry for the 16Mbit AT45DB321 */ - - priv->pageshift = 10; /* Page size = 1024/1056 bytes */ - priv->npages = 8192; /* 8192 pages */ - return OK; - - default: - return -ENODEV; - } - } - - return -ENODEV; -} - -/************************************************************************************ - * Name: at45db_rdsr - ************************************************************************************/ - -static inline uint8_t at45db_rdsr(struct at45db_dev_s *priv) -{ - uint8_t retval; - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SEND(priv->spi, AT45DB_RDSR); - retval = SPI_SEND(priv->spi, 0xff); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - return retval; -} - -/************************************************************************************ - * Name: at45db_waitbusy - ************************************************************************************/ - -static uint8_t at45db_waitbusy(struct at45db_dev_s *priv) -{ - uint8_t sr; - - /* Poll the device, waiting for it to report that it is ready */ - - do - { - up_udelay(10); - sr = (uint8_t)at45db_rdsr(priv); - } - while ((sr & AT45DB_SR_RDY) == 0); - return sr; -} - -/************************************************************************************ - * Name: at45db_pgerase - ************************************************************************************/ - -static inline void at45db_pgerase(struct at45db_dev_s *priv, off_t sector) -{ - uint8_t erasecmd[4]; - off_t offset = sector << priv->pageshift; - - fvdbg("sector: %08lx\n", (long)sector); - - /* Higher performance write logic: We leave the chip busy after write and erase - * operations. This improves write and erase performance because we do not have - * to wait as long between transactions (other processing can occur while the chip - * is busy) but means that the chip must stay powered and that we must check if - * the chip is still busy on each entry point. - */ - -#ifdef CONFIG_AT45DB_PREWAIT - at45db_waitbusy(priv); -#endif - - /* "The Page Erase command can be used to individually erase any page in the main - * memory array allowing the Buffer to Main Memory Page Program to be utilized at a - * later time. ... To perform a page erase in the binary page size ..., the - * opcode 81H must be loaded into the device, followed by three address bytes - * ... When a low-to-high transition occurs on the CS pin, the part will erase the - * selected page (the erased state is a logical 1). ... the status register and the - * RDY/BUSY pin will indicate that the part is busy." - */ - - erasecmd[0] = AT45DB_PGERASE; /* Page erase command */ - erasecmd[1] = (offset >> 16) & 0xff; /* 24-bit offset MS bytes */ - erasecmd[2] = (offset >> 8) & 0xff; /* 24-bit offset middle bytes */ - erasecmd[3] = offset & 0xff; /* 24-bit offset LS bytes */ - - /* Erase the page */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SNDBLOCK(priv->spi, erasecmd, 4); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - - /* Wait for any erase to complete if we are not trying to improve write - * performance. (see comments above). - */ - -#ifndef CONFIG_AT45DB_PREWAIT - at45db_waitbusy(priv); -#endif - fvdbg("Erased\n"); -} - -/************************************************************************************ - * Name: at32db_chiperase - ************************************************************************************/ - -static inline int at32db_chiperase(struct at45db_dev_s *priv) -{ - fvdbg("priv: %p\n", priv); - - /* Higher performance write logic: We leave the chip busy after write and erase - * operations. This improves write and erase performance because we do not have - * to wait as long between transactions (other processing can occur while the chip - * is busy) but means that the chip must stay powered and that we must check if - * the chip is still busy on each entry point. - */ - -#ifdef CONFIG_AT45DB_PREWAIT - at45db_waitbusy(priv); -#endif - - /* "The entire main memory can be erased at one time by using the Chip Erase - * command. To execute the Chip Erase command, a 4-byte command sequence C7H, 94H, - * 80H and 9AH must be clocked into the device. ... After the last bit of the opcode - * sequence has been clocked in, the CS pin can be deasserted to start the erase - * process. ... the Status Register will indicate that the device is busy. The Chip - * Erase command will not affect sectors that are protected or locked down... - */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SNDBLOCK(priv->spi, g_chiperase, CHIP_ERASE_SIZE); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - - /* Wait for any erase to complete if we are not trying to improve write - * performance. (see comments above). - */ - -#ifndef CONFIG_AT45DB_PREWAIT - at45db_waitbusy(priv); -#endif - return OK; -} - -/************************************************************************************ - * Name: at45db_pgwrite - ************************************************************************************/ - -static inline void at45db_pgwrite(struct at45db_dev_s *priv, FAR const uint8_t *buffer, - off_t page) -{ - uint8_t wrcmd [4]; - off_t offset = page << priv->pageshift; - - fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset); - - /* We assume that sectors are not write protected */ - - wrcmd[0] = AT45DB_MNTHRUBF1; /* To main memory through buffer 1 */ - wrcmd[1] = (offset >> 16) & 0xff; /* 24-bit address MS byte */ - wrcmd[2] = (offset >> 8) & 0xff; /* 24-bit address middle byte */ - wrcmd[3] = offset & 0xff; /* 24-bit address LS byte */ - - /* Higher performance write logic: We leave the chip busy after write and erase - * operations. This improves write and erase performance because we do not have - * to wait as long between transactions (other processing can occur while the chip - * is busy) but means that the chip must stay powered and that we must check if - * the chip is still busy on each entry point. - */ - -#ifdef CONFIG_AT45DB_PREWAIT - at45db_waitbusy(priv); -#endif - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SNDBLOCK(priv->spi, wrcmd, 4); - SPI_SNDBLOCK(priv->spi, buffer, 1 << priv->pageshift); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - - /* Wait for any erase to complete if we are not trying to improve write - * performance. (see comments above). - */ - -#ifndef CONFIG_AT45DB_PREWAIT - at45db_waitbusy(priv); -#endif - fvdbg("Written\n"); -} - -/************************************************************************************ - * Name: at45db_erase - ************************************************************************************/ - -static int at45db_erase(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks) -{ - FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd; - size_t pgsleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Take the lock so that we have exclusive access to the bus, then power up the - * FLASH device. - */ - - at45db_lock(priv); - at45db_resume(priv); - - /* Then erase each page */ - - while (pgsleft-- > 0) - { - /* Erase each sector */ - - at45db_pgerase(priv, startblock); - startblock++; - } - - at45db_pwrdown(priv); - at45db_unlock(priv); - return (int)nblocks; -} - -/************************************************************************************ - * Name: at45db_bread - ************************************************************************************/ - -static ssize_t at45db_bread(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks, - FAR uint8_t *buffer) -{ - FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd; - ssize_t nbytes; - - /* On this device, we can handle the block read just like the byte-oriented read */ - - nbytes = at45db_read(mtd, startblock << priv->pageshift, nblocks << priv->pageshift, buffer); - if (nbytes > 0) - { - return nbytes >> priv->pageshift; - } - return nbytes; -} - -/************************************************************************************ - * Name: at45db_bwrite - ************************************************************************************/ - -static ssize_t at45db_bwrite(FAR struct mtd_dev_s *mtd, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) -{ - FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd; - size_t pgsleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Take the lock so that we have exclusive access to the bus, then power up the - * FLASH device. - */ - - at45db_lock(priv); - at45db_resume(priv); - - /* Write each page to FLASH */ - - while (pgsleft-- > 0) - { - at45db_pgwrite(priv, buffer, startblock); - startblock++; - } - - at45db_pwrdown(priv); - at45db_unlock(priv); - - return nblocks; -} - -/************************************************************************************ - * Name: at45db_read - ************************************************************************************/ - -static ssize_t at45db_read(FAR struct mtd_dev_s *mtd, off_t offset, size_t nbytes, - FAR uint8_t *buffer) -{ - FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd; - uint8_t rdcmd [5]; - - fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); - - /* Set up for the read */ - - rdcmd[0] = AT45DB_RDARRAYHF; /* FAST_READ is safe at all supported SPI speeds. */ - rdcmd[1] = (offset >> 16) & 0xff; /* 24-bit address upper byte */ - rdcmd[2] = (offset >> 8) & 0xff; /* 24-bit address middle byte */ - rdcmd[3] = offset & 0xff; /* 24-bit address least significant byte */ - rdcmd[4] = 0; /* Dummy byte */ - - /* Take the lock so that we have exclusive access to the bus, then power up the - * FLASH device. - */ - - at45db_lock(priv); - at45db_resume(priv); - - /* Higher performance write logic: We leave the chip busy after write and erase - * operations. This improves write and erase performance because we do not have - * to wait as long between transactions (other processing can occur while the chip - * is busy) but means that the chip must stay powered and that we must check if - * the chip is still busy on each entry point. - */ - -#ifdef CONFIG_AT45DB_PREWAIT - at45db_waitbusy(priv); -#endif - - /* Perform the read */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SNDBLOCK(priv->spi, rdcmd, 5); - SPI_RECVBLOCK(priv->spi, buffer, nbytes); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - - at45db_pwrdown(priv); - at45db_unlock(priv); - - fvdbg("return nbytes: %d\n", (int)nbytes); - return nbytes; -} - -/************************************************************************************ - * Name: at45db_ioctl - ************************************************************************************/ - -static int at45db_ioctl(FAR struct mtd_dev_s *mtd, int cmd, unsigned long arg) -{ - FAR struct at45db_dev_s *priv = (FAR struct at45db_dev_s *)mtd; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - fvdbg("cmd: %d \n", cmd); - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - */ - - geo->blocksize = (1 << priv->pageshift); - geo->erasesize = geo->blocksize; - geo->neraseblocks = priv->npages; - ret = OK; - - fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); - } - } - break; - - case MTDIOC_BULKERASE: - { - /* Take the lock so that we have exclusive access to the bus, then - * power up the FLASH device. - */ - - at45db_lock(priv); - at45db_resume(priv); - - /* Erase the entire device */ - - ret = at32db_chiperase(priv); - at45db_pwrdown(priv); - at45db_unlock(priv); - } - break; - - case MTDIOC_XIPBASE: - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - fvdbg("return %d\n", ret); - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: at45db_initialize - * - * Description: - * Create an initialize MTD device instance. MTD devices are not registered - * in the file system, but are created as instances that can be bound to - * other functions (such as a block or character driver front end). - * - ************************************************************************************/ - -FAR struct mtd_dev_s *at45db_initialize(FAR struct spi_dev_s *spi) -{ - FAR struct at45db_dev_s *priv; - uint8_t sr; - int ret; - - fvdbg("spi: %p\n", spi); - - /* Allocate a state structure (we allocate the structure instead of using - * a fixed, static allocation so that we can handle multiple FLASH devices. - * The current implementation would handle only one FLASH part per SPI - * device (only because of the SPIDEV_FLASH definition) and so would have - * to be extended to handle multiple FLASH parts on the same SPI bus. - */ - - priv = (FAR struct at45db_dev_s *)kmalloc(sizeof(struct at45db_dev_s)); - if (priv) - { - /* Initialize the allocated structure */ - - priv->mtd.erase = at45db_erase; - priv->mtd.bread = at45db_bread; - priv->mtd.bwrite = at45db_bwrite; - priv->mtd.read = at45db_read; - priv->mtd.ioctl = at45db_ioctl; - priv->spi = spi; - - /* Deselect the FLASH */ - - SPI_SELECT(spi, SPIDEV_FLASH, false); - - /* Lock and configure the SPI bus. */ - - at45db_lock(priv); - at45db_resume(priv); - - /* Identify the FLASH chip and get its capacity */ - - ret = at45db_rdid(priv); - if (ret != OK) - { - /* Unrecognized! Discard all of that work we just did and return NULL */ - - fdbg("Unrecognized\n"); - goto errout; - } - - /* Get the value of the status register (as soon as the device is ready) */ - - sr = at45db_waitbusy(priv); - - /* Check if the device is configured as 256, 512 or 1024 bytes-per-page device */ - - if ((sr & AT45DB_SR_PGSIZE) == 0) - { - /* No, re-program it for the binary page size. NOTE: A power cycle - * is required after the device has be re-programmed. - */ - - fdbg("Reprogramming page size\n"); - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - SPI_SNDBLOCK(priv->spi, g_binpgsize, BINPGSIZE_SIZE); - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - goto errout; - } - - /* Release the lock and power down the device */ - - at45db_pwrdown(priv); - at45db_unlock(priv); - } - - fvdbg("Return %p\n", priv); - return (FAR struct mtd_dev_s *)priv; - -/* On any failure, we need free memory allocations and release the lock that - * we hold on the SPI bus. On failures, assume that we cannot talk to the - * device to do any more. - */ - -errout: - at45db_unlock(priv); - kfree(priv); - return NULL; -} diff --git a/nuttx/drivers/mtd/flash_eraseall.c b/nuttx/drivers/mtd/flash_eraseall.c deleted file mode 100644 index ce0cfe649..000000000 --- a/nuttx/drivers/mtd/flash_eraseall.c +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** - * drivers/mtd/flash_eraseall.c - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include -#include -#include - -/**************************************************************************** - * Private Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: flash_eraseall - * - * Description: - * Call a block driver with the MDIOC_BULKERASE ioctl command. This will - * cause the MTD driver to erase all of the flash. - * - ****************************************************************************/ - -int flash_eraseall(FAR const char *driver) -{ - FAR struct inode *inode; - FAR const struct block_operations *ops; - int ret; - - /* Open the block driver */ - - ret = open_blockdriver(driver ,0, &inode); - if (ret < 0) - { - fdbg("ERROR: Failed to open '%s': %d\n", driver, ret); - return ret; - } - - /* Get the block operations */ - - ops = inode->u.i_bops; - - /* Invoke the block driver ioctl method */ - - ret = -EPERM; - if (ops->ioctl) - { - ret = ops->ioctl(inode, MTDIOC_BULKERASE, 0); - if (ret < 0) - { - fdbg("ERROR: MTD ioctl(%04x) failed: %d\n", MTDIOC_BULKERASE, ret); - } - } - - /* Close the block driver */ - - close_blockdriver(inode); - return ret; -} diff --git a/nuttx/drivers/mtd/ftl.c b/nuttx/drivers/mtd/ftl.c deleted file mode 100644 index 6cf8f0317..000000000 --- a/nuttx/drivers/mtd/ftl.c +++ /dev/null @@ -1,601 +0,0 @@ -/**************************************************************************** - * drivers/mtd/ftl.c - * - * Copyright (C) 2009, 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/**************************************************************************** - * Private Definitions - ****************************************************************************/ - -#if defined(CONFIG_FS_READAHEAD) || (defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER)) -# defined CONFIG_FTL_RWBUFFER 1 -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct ftl_struct_s -{ - FAR struct mtd_dev_s *mtd; /* Contained MTD interface */ - struct mtd_geometry_s geo; /* Device geometry */ -#ifdef CONFIG_FTL_RWBUFFER - struct rwbuffer_s rwb; /* Read-ahead/write buffer support */ -#endif - uint16_t blkper; /* R/W blocks per erase block */ -#ifdef CONFIG_FS_WRITABLE - FAR uint8_t *eblock; /* One, in-memory erase block */ -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int ftl_open(FAR struct inode *inode); -static int ftl_close(FAR struct inode *inode); -static ssize_t ftl_reload(FAR void *priv, FAR uint8_t *buffer, - off_t startblock, size_t nblocks); -static ssize_t ftl_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors); -#ifdef CONFIG_FS_WRITABLE -static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, - off_t startblock, size_t nblocks); -static ssize_t ftl_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, unsigned int nsectors); -#endif -static int ftl_geometry(FAR struct inode *inode, struct geometry *geometry); -static int ftl_ioctl(FAR struct inode *inode, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct block_operations g_bops = -{ - ftl_open, /* open */ - ftl_close, /* close */ - ftl_read, /* read */ -#ifdef CONFIG_FS_WRITABLE - ftl_write, /* write */ -#else - NULL, /* write */ -#endif - ftl_geometry, /* geometry */ - ftl_ioctl /* ioctl */ -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ftl_open - * - * Description: Open the block device - * - ****************************************************************************/ - -static int ftl_open(FAR struct inode *inode) -{ - fvdbg("Entry\n"); - return OK; -} - -/**************************************************************************** - * Name: ftl_close - * - * Description: close the block device - * - ****************************************************************************/ - -static int ftl_close(FAR struct inode *inode) -{ - fvdbg("Entry\n"); - return OK; -} - -/**************************************************************************** - * Name: ftl_reload - * - * Description: Read the specified numer of sectors - * - ****************************************************************************/ - -static ssize_t ftl_reload(FAR void *priv, FAR uint8_t *buffer, - off_t startblock, size_t nblocks) -{ - struct ftl_struct_s *dev = (struct ftl_struct_s *)priv; - ssize_t nread; - - /* Read the full erase block into the buffer */ - - nread = MTD_BREAD(dev->mtd, startblock, nblocks, buffer); - if (nread != nblocks) - { - fdbg("Read %d blocks starting at block %d failed: %d\n", - nblocks, startblock, nread); - } - return nread; -} - -/**************************************************************************** - * Name: ftl_read - * - * Description: Read the specified numer of sectors - * - ****************************************************************************/ - -static ssize_t ftl_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - struct ftl_struct_s *dev; - - fvdbg("sector: %d nsectors: %d\n", start_sector, nsectors); - - DEBUGASSERT(inode && inode->i_private); - dev = (struct ftl_struct_s *)inode->i_private; -#ifdef CONFIG_FS_READAHEAD - return rwb_read(&dev->rwb, start_sector, nsectors, buffer); -#else - return ftl_reload(dev, buffer, start_sector, nsectors); -#endif -} - -/**************************************************************************** - * Name: ftl_flush - * - * Description: Write the specified number of sectors - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, - off_t startblock, size_t nblocks) -{ - struct ftl_struct_s *dev = (struct ftl_struct_s *)priv; - off_t alignedblock; - off_t mask; - off_t rwblock; - off_t eraseblock; - off_t offset; - size_t remaining; - size_t nxfrd; - int nbytes; - int ret; - - /* Get the aligned block. Here is is assumed: (1) The number of R/W blocks - * per erase block is a power of 2, and (2) the erase begins with that same - * alignment. - */ - - mask = dev->blkper - 1; - alignedblock = (startblock + mask) & ~mask; - - /* Handle partial erase blocks before the first unaligned block */ - - remaining = nblocks; - if (alignedblock > startblock) - { - /* Check if the write is shorter than to the end of the erase block */ - - bool short_write = (remaining < (alignedblock - startblock)); - - /* Read the full erase block into the buffer */ - - rwblock = startblock & ~mask; - nxfrd = MTD_BREAD(dev->mtd, rwblock, dev->blkper, dev->eblock); - if (nxfrd != dev->blkper) - { - fdbg("Read erase block %d failed: %d\n", rwblock, nxfrd); - return -EIO; - } - - /* Then erase the erase block */ - - eraseblock = rwblock / dev->blkper; - ret = MTD_ERASE(dev->mtd, eraseblock, 1); - if (ret < 0) - { - fdbg("Erase block=%d failed: %d\n", eraseblock, ret); - return ret; - } - - /* Copy the user data at the end of the buffered erase block */ - - offset = (startblock & mask) * dev->geo.blocksize; - - if (short_write) - { - nbytes = remaining * dev->geo.blocksize; - } - else - { - nbytes = dev->geo.erasesize - offset; - } - - fvdbg("Copy %d bytes into erase block=%d at offset=%d\n", - nbytes, eraseblock, offset); - - memcpy(dev->eblock + offset, buffer, nbytes); - - /* And write the erase back to flash */ - - nxfrd = MTD_BWRITE(dev->mtd, rwblock, dev->blkper, dev->eblock); - if (nxfrd != dev->blkper) - { - fdbg("Write erase block %d failed: %d\n", rwblock, nxfrd); - return -EIO; - } - - /* Then update for amount written */ - - if (short_write) - { - remaining = 0; - } - else - { - remaining -= dev->blkper - (startblock & mask); - } - - buffer += nbytes; - } - - /* How handle full erase pages in the middle */ - - while (remaining >= dev->blkper) - { - /* Erase the erase block */ - - eraseblock = alignedblock / dev->blkper; - ret = MTD_ERASE(dev->mtd, eraseblock, 1); - if (ret < 0) - { - fdbg("Erase block=%d failed: %d\n", eraseblock, ret); - return ret; - } - - /* Write a full erase back to flash */ - - fvdbg("Write %d bytes into erase block=%d at offset=0\n", - dev->geo.erasesize, alignedblock); - - nxfrd = MTD_BWRITE(dev->mtd, alignedblock, dev->blkper, buffer); - if (nxfrd != dev->blkper) - { - fdbg("Write erase block %d failed: %d\n", alignedblock, nxfrd); - return -EIO; - } - - /* Then update for amount written */ - - alignedblock += dev->blkper; - remaining -= dev->blkper; - buffer += dev->geo.erasesize; - } - - /* Finally, handler any partial blocks after the last full erase block */ - - if (remaining > 0) - { - /* Read the full erase block into the buffer */ - - nxfrd = MTD_BREAD(dev->mtd, alignedblock, dev->blkper, dev->eblock); - if (nxfrd != dev->blkper) - { - fdbg("Read erase block %d failed: %d\n", alignedblock, nxfrd); - return -EIO; - } - - /* Then erase the erase block */ - - eraseblock = alignedblock / dev->blkper; - ret = MTD_ERASE(dev->mtd, eraseblock, 1); - if (ret < 0) - { - fdbg("Erase block=%d failed: %d\n", eraseblock, ret); - return ret; - } - - /* Copy the user data at the beginning the buffered erase block */ - - nbytes = remaining * dev->geo.blocksize; - fvdbg("Copy %d bytes into erase block=%d at offset=0\n", - nbytes, alignedblock); - memcpy(dev->eblock, buffer, nbytes); - - /* And write the erase back to flash */ - - nxfrd = MTD_BWRITE(dev->mtd, alignedblock, dev->blkper, dev->eblock); - if (nxfrd != dev->blkper) - { - fdbg("Write erase block %d failed: %d\n", alignedblock, nxfrd); - return -EIO; - } - } - - return nblocks; -} -#endif - -/**************************************************************************** - * Name: ftl_write - * - * Description: Write (or buffer) the specified number of sectors - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static ssize_t ftl_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - struct ftl_struct_s *dev; - - fvdbg("sector: %d nsectors: %d\n", start_sector, nsectors); - - DEBUGASSERT(inode && inode->i_private); - dev = (struct ftl_struct_s *)inode->i_private; -#ifdef CONFIG_FS_WRITEBUFFER - return rwb_write(&dev->rwb, start_sector, nsectors, buffer); -#else - return ftl_flush(dev, buffer, start_sector, nsectors); -#endif -} -#endif - -/**************************************************************************** - * Name: ftl_geometry - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int ftl_geometry(FAR struct inode *inode, struct geometry *geometry) -{ - struct ftl_struct_s *dev; - - fvdbg("Entry\n"); - - DEBUGASSERT(inode); - if (geometry) - { - dev = (struct ftl_struct_s *)inode->i_private; - geometry->geo_available = true; - geometry->geo_mediachanged = false; -#ifdef CONFIG_FS_WRITABLE - geometry->geo_writeenabled = true; -#else - geometry->geo_writeenabled = false; -#endif - geometry->geo_nsectors = dev->geo.neraseblocks * dev->blkper; - geometry->geo_sectorsize = dev->geo.blocksize; - - fvdbg("available: true mediachanged: false writeenabled: %s\n", - geometry->geo_writeenabled ? "true" : "false"); - fvdbg("nsectors: %d sectorsize: %d\n", - geometry->geo_nsectors, geometry->geo_sectorsize); - - return OK; - } - return -EINVAL; -} - -/**************************************************************************** - * Name: ftl_ioctl - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int ftl_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) -{ - struct ftl_struct_s *dev ; - int ret; - - fvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - - /* Only one block driver ioctl command is supported by this driver (and - * that command is just passed on to the MTD driver in a slightly - * different form). - */ - - if (cmd == BIOC_XIPBASE) - { - /* The argument accompanying the BIOC_XIPBASE should be non-NULL. If - * DEBUG is enabled, we will catch it here instead of in the MTD - * driver. - */ - -#ifdef CONFIG_DEBUG - if (arg == 0) - { - fdbg("ERROR: BIOC_XIPBASE argument is NULL\n"); - return -EINVAL; - } -#endif - - /* Just change the BIOC_XIPBASE command to the MTDIOC_XIPBASE command. */ - - cmd = MTDIOC_XIPBASE; - } - - /* No other block driver ioctl commmands are not recognized by this - * driver. Other possible MTD driver ioctl commands are passed through - * to the MTD driver (unchanged). - */ - - dev = (struct ftl_struct_s *)inode->i_private; - ret = MTD_IOCTL(dev->mtd, cmd, arg); - if (ret < 0) - { - fdbg("ERROR: MTD ioctl(%04x) failed: %d\n", cmd, ret); - } - - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ftl_initialize - * - * Description: - * Initialize to provide a block driver wrapper around an MTD interface - * - * Input Parameters: - * minor - The minor device number. The MTD block device will be - * registered as as /dev/mtdblockN where N is the minor number. - * mtd - The MTD device that supports the FLASH interface. - * - ****************************************************************************/ - -int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd) -{ - struct ftl_struct_s *dev; - char devname[16]; - int ret = -ENOMEM; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (minor < 0 || minor > 255 || !mtd) - { - return -EINVAL; - } -#endif - - /* Allocate a FTL device structure */ - - dev = (struct ftl_struct_s *)kmalloc(sizeof(struct ftl_struct_s)); - if (dev) - { - /* Initialize the FTL device structure */ - - dev->mtd = mtd; - - /* Get the device geometry. (casting to uintptr_t first eliminates - * complaints on some architectures where the sizeof long is different - * from the size of a pointer). - */ - - ret = MTD_IOCTL(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&dev->geo)); - if (ret < 0) - { - fdbg("MTD ioctl(MTDIOC_GEOMETRY) failed: %d\n", ret); - kfree(dev); - return ret; - } - - /* Allocate one, in-memory erase block buffer */ - -#ifdef CONFIG_FS_WRITABLE - dev->eblock = (FAR uint8_t *)kmalloc(dev->geo.erasesize); - if (!dev->eblock) - { - fdbg("Failed to allocate an erase block buffer\n"); - kfree(dev); - return -ENOMEM; - } -#endif - - /* Get the number of R/W blocks per erase block */ - - dev->blkper = dev->geo.erasesize / dev->geo.blocksize; - DEBUGASSERT(dev->blkper * dev->geo.blocksize == dev->geo.erasesize); - - /* Configure read-ahead/write buffering */ - -#ifdef CONFIG_FTL_RWBUFFER - dev->rwb.blocksize = dev->geo.blocksize; - dev->rwb.nblocks = dev->geo.neraseblocks * dev->blkper; - dev->rwb.dev = (FAR void *)dev; - -#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER) - dev->rwb.wrmaxblocks = dev->blkper; - dev->rwb.wrflush = ftl_flush; -#endif - -#ifdef CONFIG_FS_READAHEAD - dev->rwb.rhmaxblocks = dev->blkper; - dev->rwb.rhreload = ftl_reload; -#endif - ret = rwb_initialize(&dev->rwb); - if (ret < 0) - { - fdbg("rwb_initialize failed: %d\n", ret); - kfree(dev); - return ret; - } -#endif - - /* Create a MTD block device name */ - - snprintf(devname, 16, "/dev/mtdblock%d", minor); - - /* Inode private data is a reference to the FTL device structure */ - - ret = register_blockdriver(devname, &g_bops, 0, dev); - if (ret < 0) - { - fdbg("register_blockdriver failed: %d\n", -ret); - kfree(dev); - } - } - return ret; -} diff --git a/nuttx/drivers/mtd/m25px.c b/nuttx/drivers/mtd/m25px.c deleted file mode 100644 index 4f96c5a3b..000000000 --- a/nuttx/drivers/mtd/m25px.c +++ /dev/null @@ -1,798 +0,0 @@ -/************************************************************************************ - * drivers/mtd/m25px.c - * Driver for SPI-based M25P1 (128Kbit), M25P64 (32Mbit), M25P64 (64Mbit), and - * M25P128 (128Mbit) FLASH (and compatible). - * - * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ -/* Configuration ********************************************************************/ -/* Per the data sheet, MP25P10 parts can be driven with either SPI mode 0 (CPOL=0 and - * CPHA=0) or mode 3 (CPOL=1 and CPHA=1). But I have heard that other devices can - * operated in mode 0 or 1. So you may need to specify CONFIG_MP25P_SPIMODE to - * select the best mode for your device. If CONFIG_MP25P_SPIMODE is not defined, - * mode 0 will be used. - */ - -#ifndef CONFIG_MP25P_SPIMODE -# define CONFIG_MP25P_SPIMODE SPIDEV_MODE0 -#endif - -/* Various manufacturers may have produced the parts. 0x20 is the manufacturer ID - * for the STMicro MP25x serial FLASH. If, for example, you are using the a Macronix - * International MX25 serial FLASH, the correct manufacturer ID would be 0xc2. - */ - -#ifndef CONFIG_MP25P_MANUFACTURER -# define CONFIG_MP25P_MANUFACTURER 0x20 -#endif - -/* M25P Registers *******************************************************************/ -/* Indentification register values */ - -#define M25P_MANUFACTURER CONFIG_MP25P_MANUFACTURER -#define M25P_MEMORY_TYPE 0x20 -#define M25P_M25P1_CAPACITY 0x11 /* 1 M-bit */ -#define M25P_M25P32_CAPACITY 0x16 /* 32 M-bit */ -#define M25P_M25P64_CAPACITY 0x17 /* 64 M-bit */ -#define M25P_M25P128_CAPACITY 0x18 /* 128 M-bit */ - -/* M25P1 capacity is 131,072 bytes: - * (4 sectors) * (32,768 bytes per sector) - * (512 pages) * (256 bytes per page) - */ - -#define M25P_M25P1_SECTOR_SHIFT 15 /* Sector size 1 << 15 = 65,536 */ -#define M25P_M25P1_NSECTORS 4 -#define M25P_M25P1_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ -#define M25P_M25P1_NPAGES 512 - -/* M25P32 capacity is 4,194,304 bytes: - * (64 sectors) * (65,536 bytes per sector) - * (16384 pages) * (256 bytes per page) - */ - -#define M25P_M25P32_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ -#define M25P_M25P32_NSECTORS 64 -#define M25P_M25P32_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ -#define M25P_M25P32_NPAGES 16384 - -/* M25P64 capacity is 8,338,608 bytes: - * (128 sectors) * (65,536 bytes per sector) - * (32768 pages) * (256 bytes per page) - */ - -#define M25P_M25P64_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ -#define M25P_M25P64_NSECTORS 128 -#define M25P_M25P64_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ -#define M25P_M25P64_NPAGES 32768 - -/* M25P128 capacity is 16,777,216 bytes: - * (64 sectors) * (262,144 bytes per sector) - * (65536 pages) * (256 bytes per page) - */ - -#define M25P_M25P128_SECTOR_SHIFT 18 /* Sector size 1 << 18 = 262,144 */ -#define M25P_M25P128_NSECTORS 64 -#define M25P_M25P128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ -#define M25P_M25P128_NPAGES 65536 - -/* Instructions */ -/* Command Value N Description Addr Dummy Data */ -#define M25P_WREN 0x06 /* 1 Write Enable 0 0 0 */ -#define M25P_WRDI 0x04 /* 1 Write Disable 0 0 0 */ -#define M25P_RDID 0x9f /* 1 Read Identification 0 0 1-3 */ -#define M25P_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */ -#define M25P_WRSR 0x01 /* 1 Write Status Register 0 0 1 */ -#define M25P_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */ -#define M25P_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */ -#define M25P_PP 0x02 /* 1 Page Program 3 0 1-256 */ -#define M25P_SE 0xd8 /* 1 Sector Erase 3 0 0 */ -#define M25P_BE 0xc7 /* 1 Bulk Erase 0 0 0 */ -#define M25P_DP 0xb9 /* 2 Deep power down 0 0 0 */ -#define M25P_RES 0xab /* 2 Read Electronic Signature 0 3 >=1 */ - -/* NOTE 1: All parts, NOTE 2: M25P632/M25P64 */ - -/* Status register bit definitions */ - -#define M25P_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */ -#define M25P_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */ -#define M25P_SR_BP_SHIFT (2) /* Bits 2-4: Block protect bits */ -#define M25P_SR_BP_MASK (7 << M25P_SR_BP_SHIFT) -# define M25P_SR_BP_NONE (0 << M25P_SR_BP_SHIFT) /* Unprotected */ -# define M25P_SR_BP_UPPER64th (1 << M25P_SR_BP_SHIFT) /* Upper 64th */ -# define M25P_SR_BP_UPPER32nd (2 << M25P_SR_BP_SHIFT) /* Upper 32nd */ -# define M25P_SR_BP_UPPER16th (3 << M25P_SR_BP_SHIFT) /* Upper 16th */ -# define M25P_SR_BP_UPPER8th (4 << M25P_SR_BP_SHIFT) /* Upper 8th */ -# define M25P_SR_BP_UPPERQTR (5 << M25P_SR_BP_SHIFT) /* Upper quarter */ -# define M25P_SR_BP_UPPERHALF (6 << M25P_SR_BP_SHIFT) /* Upper half */ -# define M25P_SR_BP_ALL (7 << M25P_SR_BP_SHIFT) /* All sectors */ - /* Bits 5-6: Unused, read zero */ -#define M25P_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */ - -#define M25P_DUMMY 0xa5 - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s - * must appear at the beginning of the definition so that you can freely - * cast between pointers to struct mtd_dev_s and struct m25p_dev_s. - */ - -struct m25p_dev_s -{ - struct mtd_dev_s mtd; /* MTD interface */ - FAR struct spi_dev_s *dev; /* Saved SPI interface instance */ - uint8_t sectorshift; /* 16 or 18 */ - uint8_t pageshift; /* 8 */ - uint16_t nsectors; /* 128 or 64 */ - uint32_t npages; /* 32,768 or 65,536 */ -}; - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/* Helpers */ - -static void m25p_lock(FAR struct spi_dev_s *dev); -static inline void m25p_unlock(FAR struct spi_dev_s *dev); -static inline int m25p_readid(struct m25p_dev_s *priv); -static void m25p_waitwritecomplete(struct m25p_dev_s *priv); -static void m25p_writeenable(struct m25p_dev_s *priv); -static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t offset); -static inline int m25p_bulkerase(struct m25p_dev_s *priv); -static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer, - off_t offset); - -/* MTD driver methods */ - -static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buf); -static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); -static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: m25p_lock - ************************************************************************************/ - -static void m25p_lock(FAR struct spi_dev_s *dev) -{ - /* On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of - * transfers. The bus should be locked before the chip is selected. - * - * This is a blocking call and will not return until we have exclusiv access to - * the SPI buss. We will retain that exclusive access until the bus is unlocked. - */ - - (void)SPI_LOCK(dev, true); - - /* After locking the SPI bus, the we also need call the setfrequency, setbits, and - * setmode methods to make sure that the SPI is properly configured for the device. - * If the SPI buss is being shared, then it may have been left in an incompatible - * state. - */ - - SPI_SETMODE(dev, CONFIG_MP25P_SPIMODE); - SPI_SETBITS(dev, 8); - (void)SPI_SETFREQUENCY(dev, 20000000); -} - -/************************************************************************************ - * Name: m25p_unlock - ************************************************************************************/ - -static inline void m25p_unlock(FAR struct spi_dev_s *dev) -{ - (void)SPI_LOCK(dev, false); -} - -/************************************************************************************ - * Name: m25p_readid - ************************************************************************************/ - -static inline int m25p_readid(struct m25p_dev_s *priv) -{ - uint16_t manufacturer; - uint16_t memory; - uint16_t capacity; - - fvdbg("priv: %p\n", priv); - - /* Lock the SPI bus, configure the bus, and select this FLASH part. */ - - m25p_lock(priv->dev); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Read ID (RDID)" command and read the first three ID bytes */ - - (void)SPI_SEND(priv->dev, M25P_RDID); - manufacturer = SPI_SEND(priv->dev, M25P_DUMMY); - memory = SPI_SEND(priv->dev, M25P_DUMMY); - capacity = SPI_SEND(priv->dev, M25P_DUMMY); - - /* Deselect the FLASH and unlock the bus */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - m25p_unlock(priv->dev); - - fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n", - manufacturer, memory, capacity); - - /* Check for a valid manufacturer and memory type */ - - if (manufacturer == M25P_MANUFACTURER && memory == M25P_MEMORY_TYPE) - { - /* Okay.. is it a FLASH capacity that we understand? */ - - if (capacity == M25P_M25P1_CAPACITY) - { - /* Save the FLASH geometry */ - - priv->sectorshift = M25P_M25P1_SECTOR_SHIFT; - priv->nsectors = M25P_M25P1_NSECTORS; - priv->pageshift = M25P_M25P1_PAGE_SHIFT; - priv->npages = M25P_M25P1_NPAGES; - return OK; - } - else if (capacity == M25P_M25P32_CAPACITY) - { - /* Save the FLASH geometry */ - - priv->sectorshift = M25P_M25P32_SECTOR_SHIFT; - priv->nsectors = M25P_M25P32_NSECTORS; - priv->pageshift = M25P_M25P32_PAGE_SHIFT; - priv->npages = M25P_M25P32_NPAGES; - return OK; - } - else if (capacity == M25P_M25P64_CAPACITY) - { - /* Save the FLASH geometry */ - - priv->sectorshift = M25P_M25P64_SECTOR_SHIFT; - priv->nsectors = M25P_M25P64_NSECTORS; - priv->pageshift = M25P_M25P64_PAGE_SHIFT; - priv->npages = M25P_M25P64_NPAGES; - return OK; - } - else if (capacity == M25P_M25P128_CAPACITY) - { - /* Save the FLASH geometry */ - - priv->sectorshift = M25P_M25P128_SECTOR_SHIFT; - priv->nsectors = M25P_M25P128_NSECTORS; - priv->pageshift = M25P_M25P128_PAGE_SHIFT; - priv->npages = M25P_M25P128_NPAGES; - return OK; - } - } - - return -ENODEV; -} - -/************************************************************************************ - * Name: m25p_waitwritecomplete - ************************************************************************************/ - -static void m25p_waitwritecomplete(struct m25p_dev_s *priv) -{ - uint8_t status; - - /* Are we the only device on the bus? */ - -#ifdef CONFIG_SPI_OWNBUS - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->dev, M25P_RDSR); - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->dev, M25P_DUMMY); - } - while ((status & M25P_SR_WIP) != 0); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - -#else - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->dev, M25P_RDSR); - - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->dev, M25P_DUMMY); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - - /* Given that writing could take up to few tens of milliseconds, and erasing - * could take more. The following short delay in the "busy" case will allow - * other peripherals to access the SPI bus. - */ - - if ((status & M25P_SR_WIP) != 0) - { - m25p_unlock(priv->dev); - usleep(1000); - m25p_lock(priv->dev); - } - } - while ((status & M25P_SR_WIP) != 0); -#endif - - fvdbg("Complete\n"); -} - -/************************************************************************************ - * Name: m25p_writeenable - ************************************************************************************/ - -static void m25p_writeenable(struct m25p_dev_s *priv) -{ - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Write Enable (WREN)" command */ - - (void)SPI_SEND(priv->dev, M25P_WREN); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Enabled\n"); -} - -/************************************************************************************ - * Name: m25p_sectorerase - ************************************************************************************/ - -static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector) -{ - off_t offset = sector << priv->sectorshift; - - fvdbg("sector: %08lx\n", (long)sector); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - m25p_waitwritecomplete(priv); - - /* Send write enable instruction */ - - m25p_writeenable(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Sector Erase (SE)" instruction */ - - (void)SPI_SEND(priv->dev, M25P_SE); - - /* Send the sector offset high byte first. For all of the supported - * parts, the sector number is completely contained in the first byte - * and the values used in the following two bytes don't really matter. - */ - - (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); - (void)SPI_SEND(priv->dev, offset & 0xff); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Erased\n"); -} - -/************************************************************************************ - * Name: m25p_bulkerase - ************************************************************************************/ - -static inline int m25p_bulkerase(struct m25p_dev_s *priv) -{ - fvdbg("priv: %p\n", priv); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - m25p_waitwritecomplete(priv); - - /* Send write enable instruction */ - - m25p_writeenable(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Bulk Erase (BE)" instruction */ - - (void)SPI_SEND(priv->dev, M25P_BE); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Return: OK\n"); - return OK; -} - -/************************************************************************************ - * Name: m25p_pagewrite - ************************************************************************************/ - -static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer, - off_t page) -{ - off_t offset = page << priv->pageshift; - - fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - m25p_waitwritecomplete(priv); - - /* Enable the write access to the FLASH */ - - m25p_writeenable(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Page Program (PP)" command */ - - (void)SPI_SEND(priv->dev, M25P_PP); - - /* Send the page offset high byte first. */ - - (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); - (void)SPI_SEND(priv->dev, offset & 0xff); - - /* Then write the specified number of bytes */ - - SPI_SNDBLOCK(priv->dev, buffer, 1 << priv->pageshift); - - /* Deselect the FLASH: Chip Select high */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Written\n"); -} - -/************************************************************************************ - * Name: m25p_erase - ************************************************************************************/ - -static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ - FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; - size_t blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock access to the SPI bus until we complete the erase */ - - m25p_lock(priv->dev); - while (blocksleft-- > 0) - { - /* Erase each sector */ - - m25p_sectorerase(priv, startblock); - startblock++; - } - m25p_unlock(priv->dev); - return (int)nblocks; -} - -/************************************************************************************ - * Name: m25p_bread - ************************************************************************************/ - -static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buffer) -{ - FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; - ssize_t nbytes; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* On this device, we can handle the block read just like the byte-oriented read */ - - nbytes = m25p_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer); - if (nbytes > 0) - { - return nbytes >> priv->pageshift; - } - return (int)nbytes; -} - -/************************************************************************************ - * Name: m25p_bwrite - ************************************************************************************/ - -static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) -{ - FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; - size_t blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock the SPI bus and write each page to FLASH */ - - m25p_lock(priv->dev); - while (blocksleft-- > 0) - { - m25p_pagewrite(priv, buffer, startblock); - startblock++; - } - m25p_unlock(priv->dev); - - return nblocks; -} - -/************************************************************************************ - * Name: m25p_read - ************************************************************************************/ - -static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer) -{ - FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; - - fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - m25p_waitwritecomplete(priv); - - /* Lock the SPI bus and select this FLASH part */ - - m25p_lock(priv->dev); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read from Memory " instruction */ - - (void)SPI_SEND(priv->dev, M25P_READ); - - /* Send the page offset high byte first. */ - - (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); - (void)SPI_SEND(priv->dev, offset & 0xff); - - /* Then read all of the requested bytes */ - - SPI_RECVBLOCK(priv->dev, buffer, nbytes); - - /* Deselect the FLASH and unlock the SPI bus */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - m25p_unlock(priv->dev); - fvdbg("return nbytes: %d\n", (int)nbytes); - return nbytes; -} - -/************************************************************************************ - * Name: m25p_ioctl - ************************************************************************************/ - -static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - fvdbg("cmd: %d \n", cmd); - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - */ - - geo->blocksize = (1 << priv->pageshift); - geo->erasesize = (1 << priv->sectorshift); - geo->neraseblocks = priv->nsectors; - ret = OK; - - fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); - } - } - break; - - case MTDIOC_BULKERASE: - { - /* Erase the entire device */ - - m25p_lock(priv->dev); - ret = m25p_bulkerase(priv); - m25p_unlock(priv->dev); - } - break; - - case MTDIOC_XIPBASE: - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - fvdbg("return %d\n", ret); - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: m25p_initialize - * - * Description: - * Create an initialize MTD device instance. MTD devices are not registered - * in the file system, but are created as instances that can be bound to - * other functions (such as a block or character driver front end). - * - ************************************************************************************/ - -FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev) -{ - FAR struct m25p_dev_s *priv; - int ret; - - fvdbg("dev: %p\n", dev); - - /* Allocate a state structure (we allocate the structure instead of using - * a fixed, static allocation so that we can handle multiple FLASH devices. - * The current implementation would handle only one FLASH part per SPI - * device (only because of the SPIDEV_FLASH definition) and so would have - * to be extended to handle multiple FLASH parts on the same SPI bus. - */ - - priv = (FAR struct m25p_dev_s *)kmalloc(sizeof(struct m25p_dev_s)); - if (priv) - { - /* Initialize the allocated structure */ - - priv->mtd.erase = m25p_erase; - priv->mtd.bread = m25p_bread; - priv->mtd.bwrite = m25p_bwrite; - priv->mtd.read = m25p_read; - priv->mtd.ioctl = m25p_ioctl; - priv->dev = dev; - - /* Deselect the FLASH */ - - SPI_SELECT(dev, SPIDEV_FLASH, false); - - /* Identify the FLASH chip and get its capacity */ - - ret = m25p_readid(priv); - if (ret != OK) - { - /* Unrecognized! Discard all of that work we just did and return NULL */ - - fdbg("Unrecognized\n"); - kfree(priv); - priv = NULL; - } - } - - /* Return the implementation-specific state structure as the MTD device */ - - fvdbg("Return %p\n", priv); - return (FAR struct mtd_dev_s *)priv; -} diff --git a/nuttx/drivers/mtd/rammtd.c b/nuttx/drivers/mtd/rammtd.c deleted file mode 100644 index 82a7191ea..000000000 --- a/nuttx/drivers/mtd/rammtd.c +++ /dev/null @@ -1,417 +0,0 @@ -/**************************************************************************** - * drivers/mtd/rammtd.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ - -#ifndef CONFIG_RAMMTD_BLOCKSIZE -# define CONFIG_RAMMTD_BLOCKSIZE 512 -#endif - -#ifndef CONFIG_RAMMTD_ERASESIZE -# define CONFIG_RAMMTD_ERASESIZE 4096 -#endif - -#ifndef CONFIG_RAMMTD_ERASESTATE -# define CONFIG_RAMMTD_ERASESTATE 0xff -#endif - -#if CONFIG_RAMMTD_ERASESTATE != 0xff && CONFIG_RAMMTD_ERASESTATE != 0x00 -# error "Unsupported value for CONFIG_RAMMTD_ERASESTATE" -#endif - -#if CONFIG_RAMMTD_BLOCKSIZE > CONFIG_RAMMTD_ERASESIZE -# error "Must have CONFIG_RAMMTD_BLOCKSIZE <= CONFIG_RAMMTD_ERASESIZE" -#endif - -#undef CONFIG_RAMMTD_BLKPER -#define CONFIG_RAMMTD_BLKPER (CONFIG_RAMMTD_ERASESIZE/CONFIG_RAMMTD_BLOCKSIZE) - -#if CONFIG_RAMMTD_BLKPER*CONFIG_RAMMTD_BLOCKSIZE != CONFIG_RAMMTD_ERASESIZE -# error "CONFIG_RAMMTD_ERASESIZE must be an even multiple of CONFIG_RAMMTD_BLOCKSIZE" -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s - * must appear at the beginning of the definition so that you can freely - * cast between pointers to struct mtd_dev_s and struct ram_dev_s. - */ - -struct ram_dev_s -{ - struct mtd_dev_s mtd; /* MTD device */ - FAR uint8_t *start; /* Start of RAM */ - size_t nblocks; /* Number of erase blocks */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* The RAM MTD driver may be useful just as it is, but another good use of - * the RAM MTD driver is as a FLASH simulation -- to support testing of FLASH - * based logic without having FLASH. CONFIG_RAMMTD_FLASHSIM will add some - * extra logic to improve the level of FLASH simulation. - */ - -#define ram_read(dest, src, len) memcpy(dest, src, len) -#ifdef CONFIG_RAMMTD_FLASHSIM -static void *ram_write(FAR void *dest, FAR const void *src, size_t len); -#else -# define ram_write(dest, src, len) memcpy(dest, src, len) -#endif - -/* MTD driver methods */ - -static int ram_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t ram_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buf); -static ssize_t ram_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buf); -static int ram_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ram_write - ****************************************************************************/ - -#ifdef CONFIG_RAMMTD_FLASHSIM -static void *ram_write(FAR void *dest, FAR const void *src, size_t len) -{ - FAR uint8_t *pout = (FAR uint8_t *)dest; - FAR const uint8_t *pin = (FAR const uint8_t *)src; - - while (len-- > 0) - { - /* Get the source and destination values */ - - uint8_t oldvalue = *pout; - uint8_t srcvalue = *pin++; - uint8_t newvalue; - - /* Get the new destination value, accounting for bits that cannot be - * changes because they are not in the erased state. - */ - -#if CONFIG_RAMMTD_ERASESTATE == 0xff - newvalue = oldvalue & srcvalue; /* We can only clear bits */ -#else /* CONFIG_RAMMTD_ERASESTATE == 0x00 */ - newvalue = oldvalue | srcvalue; /* We can only set bits */ -#endif - - /* Report any attempt to change the value of bits that are not in the - * erased state. - */ - -#ifdef CONFIG_DEBUG - if (newvalue != srcvalue) - { - dbg("ERROR: Bad write: source=%02x dest=%02x result=%02x\n", - srcvalue, oldvalue, newvalue); - } -#endif - - /* Write the modified value to simulated FLASH */ - - *pout++ = newvalue; - } - - return dest; -} -#endif - -/**************************************************************************** - * Name: ram_erase - ****************************************************************************/ - -static int ram_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ - FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev; - off_t offset; - size_t nbytes; - - DEBUGASSERT(dev); - - /* Don't let the erase exceed the size of the ram buffer */ - - if (startblock >= priv->nblocks) - { - return 0; - } - - if (startblock + nblocks > priv->nblocks) - { - nblocks = priv->nblocks - startblock; - } - - /* Convert the erase block to a logical block and the number of blocks - * in logical block numbers - */ - - startblock *= CONFIG_RAMMTD_BLKPER; - nblocks *= CONFIG_RAMMTD_BLKPER; - - /* Get the offset corresponding to the first block and the size - * corresponding to the number of blocks. - */ - - offset = startblock * CONFIG_RAMMTD_BLOCKSIZE; - nbytes = nblocks * CONFIG_RAMMTD_BLOCKSIZE; - - /* Then erase the data in RAM */ - - memset(&priv->start[offset], CONFIG_RAMMTD_ERASESTATE, nbytes); - return OK; -} - -/**************************************************************************** - * Name: ram_bread - ****************************************************************************/ - -static ssize_t ram_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buf) -{ - FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev; - off_t offset; - off_t maxblock; - size_t nbytes; - - DEBUGASSERT(dev && buf); - - /* Don't let the read exceed the size of the ram buffer */ - - maxblock = priv->nblocks * CONFIG_RAMMTD_BLKPER; - if (startblock >= maxblock) - { - return 0; - } - - if (startblock + nblocks > maxblock) - { - nblocks = maxblock - startblock; - } - - /* Get the offset corresponding to the first block and the size - * corresponding to the number of blocks. - */ - - offset = startblock * CONFIG_RAMMTD_BLOCKSIZE; - nbytes = nblocks * CONFIG_RAMMTD_BLOCKSIZE; - - /* Then read the data frp, RAM */ - - ram_read(buf, &priv->start[offset], nbytes); - return nblocks; -} - -/**************************************************************************** - * Name: ram_bwrite - ****************************************************************************/ - -static ssize_t ram_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf) -{ - FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev; - off_t offset; - off_t maxblock; - size_t nbytes; - - DEBUGASSERT(dev && buf); - - /* Don't let the write exceed the size of the ram buffer */ - - maxblock = priv->nblocks * CONFIG_RAMMTD_BLKPER; - if (startblock >= maxblock) - { - return 0; - } - - if (startblock + nblocks > maxblock) - { - nblocks = maxblock - startblock; - } - - /* Get the offset corresponding to the first block and the size - * corresponding to the number of blocks. - */ - - offset = startblock * CONFIG_RAMMTD_BLOCKSIZE; - nbytes = nblocks * CONFIG_RAMMTD_BLOCKSIZE; - - /* Then write the data to RAM */ - - ram_write(&priv->start[offset], buf, nbytes); - return nblocks; -} - -/**************************************************************************** - * Name: ram_ioctl - ****************************************************************************/ - -static int ram_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - */ - - geo->blocksize = CONFIG_RAMMTD_BLOCKSIZE; - geo->erasesize = CONFIG_RAMMTD_ERASESIZE; - geo->neraseblocks = priv->nblocks; - ret = OK; - } - } - break; - - case MTDIOC_XIPBASE: - { - FAR void **ppv = (FAR void**)((uintptr_t)arg); - if (ppv) - { - /* Return (void*) base address of device memory */ - - *ppv = (FAR void*)priv->start; - ret = OK; - } - } - break; - - case MTDIOC_BULKERASE: - { - size_t size = priv->nblocks * CONFIG_RAMMTD_ERASESIZE; - - /* Erase the entire device */ - - memset(priv->start, CONFIG_RAMMTD_ERASESTATE, size); - ret = OK; - } - break; - - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: rammtd_initialize - * - * Description: - * Create and initialize a RAM MTD device instance. - * - * Input Parameters: - * start - Address of the beginning of the allocated RAM regions. - * size - The size in bytes of the allocated RAM region. - * - ****************************************************************************/ - -FAR struct mtd_dev_s *rammtd_initialize(FAR uint8_t *start, size_t size) -{ - FAR struct ram_dev_s *priv; - size_t nblocks; - - /* Create an instance of the RAM MTD device state structure */ - - priv = (FAR struct ram_dev_s *)kmalloc(sizeof(struct ram_dev_s)); - if (!priv) - { - fdbg("Failed to allocate the RAM MTD state structure\n"); - return NULL; - } - - /* Force the size to be an even number of the erase block size */ - - nblocks = size / CONFIG_RAMMTD_ERASESIZE; - if (nblocks <= 0) - { - fdbg("Need to provide at least one full erase block\n"); - return NULL; - } - - /* Perform initialization as necessary */ - - priv->mtd.erase = ram_erase; - priv->mtd.bread = ram_bread; - priv->mtd.bwrite = ram_bwrite; - priv->mtd.ioctl = ram_ioctl; - priv->mtd.erase = ram_erase; - - priv->start = start; - priv->nblocks = nblocks; - return &priv->mtd; -} diff --git a/nuttx/drivers/mtd/ramtron.c b/nuttx/drivers/mtd/ramtron.c deleted file mode 100644 index 34273bccf..000000000 --- a/nuttx/drivers/mtd/ramtron.c +++ /dev/null @@ -1,686 +0,0 @@ -/************************************************************************************ - * drivers/mtd/ramtron.c - * Driver for SPI-based RAMTRON NVRAM Devices FM25V10 and others (not tested) - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * Copyright (C) 2009-2010, 2012 Gregory Nutt. All rights reserved. - * Author: Uros Platise - * Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/* OPTIONS: - * - additional non-jedec standard device: FM25H20 - * must be enabled with the CONFIG_RAMTRON_FRAM_NON_JEDEC=y - * - * NOTE: - * - frequency is fixed to desired max by RAMTRON_INIT_CLK_MAX - * if new devices with different speed arrive, then SETFREQUENCY() - * needs to handle freq changes and INIT_CLK_MAX must be reduced - * to fit all devices. Note that STM32_SPI driver is prone to - * too high freq. parameters and limit it within physical constraints. - * - * TODO: - * - add support for sleep - * - add support for faster read FSTRD command - */ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -/* RAMTRON devices are flat! - * For purpose of the VFAT file system we emulate the following configuration: - */ - -#define RAMTRON_EMULATE_SECTOR_SHIFT 9 -#define RAMTRON_EMULATE_PAGE_SHIFT 9 - -/* RAMTRON Indentification register values */ - -#define RAMTRON_MANUFACTURER 0x7F -#define RAMTRON_MEMORY_TYPE 0xC2 - -/* Instructions: - * Command Value N Description Addr Dummy Data */ -#define RAMTRON_WREN 0x06 /* 1 Write Enable 0 0 0 */ -#define RAMTRON_WRDI 0x04 /* 1 Write Disable 0 0 0 */ -#define RAMTRON_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */ -#define RAMTRON_WRSR 0x01 /* 1 Write Status Register 0 0 1 */ -#define RAMTRON_READ 0x03 /* 1 Read Data Bytes A 0 >=1 */ -#define RAMTRON_FSTRD 0x0b /* 1 Higher speed read A 1 >=1 */ -#define RAMTRON_WRITE 0x02 /* 1 Write A 0 1-256 */ -#define RAMTRON_SLEEP 0xb9 // TODO: -#define RAMTRON_RDID 0x9f /* 1 Read Identification 0 0 1-3 */ -#define RAMTRON_SN 0xc3 // TODO: - - -/* Status register bit definitions */ - -#define RAMTRON_SR_WIP (1 << 0) /* Bit 0: Write in progress bit */ -#define RAMTRON_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */ -#define RAMTRON_SR_BP_SHIFT (2) /* Bits 2-4: Block protect bits */ -#define RAMTRON_SR_BP_MASK (7 << RAMTRON_SR_BP_SHIFT) -# define RAMTRON_SR_BP_NONE (0 << RAMTRON_SR_BP_SHIFT) /* Unprotected */ -# define RAMTRON_SR_BP_UPPER64th (1 << RAMTRON_SR_BP_SHIFT) /* Upper 64th */ -# define RAMTRON_SR_BP_UPPER32nd (2 << RAMTRON_SR_BP_SHIFT) /* Upper 32nd */ -# define RAMTRON_SR_BP_UPPER16th (3 << RAMTRON_SR_BP_SHIFT) /* Upper 16th */ -# define RAMTRON_SR_BP_UPPER8th (4 << RAMTRON_SR_BP_SHIFT) /* Upper 8th */ -# define RAMTRON_SR_BP_UPPERQTR (5 << RAMTRON_SR_BP_SHIFT) /* Upper quarter */ -# define RAMTRON_SR_BP_UPPERHALF (6 << RAMTRON_SR_BP_SHIFT) /* Upper half */ -# define RAMTRON_SR_BP_ALL (7 << RAMTRON_SR_BP_SHIFT) /* All sectors */ -#define RAMTRON_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */ - -#define RAMTRON_DUMMY 0xa5 - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -struct ramtron_parts_s -{ - const char *name; - uint8_t id1; - uint8_t id2; - uint32_t size; - uint8_t addr_len; - uint32_t speed; -}; - -/* This type represents the state of the MTD device. The struct mtd_dev_s - * must appear at the beginning of the definition so that you can freely - * cast between pointers to struct mtd_dev_s and struct ramtron_dev_s. - */ - -struct ramtron_dev_s -{ - struct mtd_dev_s mtd; /* MTD interface */ - FAR struct spi_dev_s *dev; /* Saved SPI interface instance */ - uint8_t sectorshift; - uint8_t pageshift; - uint16_t nsectors; - uint32_t npages; - const struct ramtron_parts_s *part; /* part instance */ -}; - -/************************************************************************************ - * Supported Part Lists - ************************************************************************************/ - -/* Defines the initial speed compatible with all devices. In case of RAMTRON - * the defined devices within the part list have all the same speed. - */ - -#define RAMTRON_INIT_CLK_MAX 40000000UL - -static struct ramtron_parts_s ramtron_parts[] = -{ - { - "FM25V02", /* name */ - 0x22, /* id1 */ - 0x00, /* id2 */ - 32L*1024L, /* size */ - 2, /* addr_len */ - 40000000 /* speed */ - }, - { - "FM25VN02", /* name */ - 0x22, /* id1 */ - 0x01, /* id2 */ - 32L*1024L, /* size */ - 2, /* addr_len */ - 40000000 /* speed */ - }, - { - "FM25V05", /* name */ - 0x23, /* id1 */ - 0x00, /* id2 */ - 64L*1024L, /* size */ - 2, /* addr_len */ - 40000000 /* speed */ - }, - { - "FM25VN05", /* name */ - 0x23, /* id1 */ - 0x01, /* id2 */ - 64L*1024L, /* size */ - 2, /* addr_len */ - 40000000 /* speed */ - }, - { - "FM25V10", /* name */ - 0x24, /* id1 */ - 0x00, /* id2 */ - 128L*1024L, /* size */ - 3, /* addr_len */ - 40000000 /* speed */ - }, - { - "FM25VN10", /* name */ - 0x24, /* id1 */ - 0x01, /* id2 */ - 128L*1024L, /* size */ - 3, /* addr_len */ - 40000000 /* speed */ - }, -#ifdef CONFIG_RAMTRON_FRAM_NON_JEDEC - { - "FM25H20", /* name */ - 0xff, /* id1 */ - 0xff, /* id2 */ - 256L*1024L, /* size */ - 3, /* addr_len */ - 40000000 /* speed */ - }, - { - NULL, /* name */ - 0, /* id1 */ - 0, /* id2 */ - 0, /* size */ - 0, /* addr_len */ - 0 /* speed */ - } -#endif -}; - - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/* Helpers */ - -static void ramtron_lock(FAR struct spi_dev_s *dev); -static inline void ramtron_unlock(FAR struct spi_dev_s *dev); -static inline int ramtron_readid(struct ramtron_dev_s *priv); -static void ramtron_waitwritecomplete(struct ramtron_dev_s *priv); -static void ramtron_writeenable(struct ramtron_dev_s *priv); -static inline void ramtron_pagewrite(struct ramtron_dev_s *priv, FAR const uint8_t *buffer, - off_t offset); - -/* MTD driver methods */ - -static int ramtron_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t ramtron_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buf); -static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); -static ssize_t ramtron_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: ramtron_lock - ************************************************************************************/ - -static void ramtron_lock(FAR struct spi_dev_s *dev) -{ - /* On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of - * transfers. The bus should be locked before the chip is selected. - * - * This is a blocking call and will not return until we have exclusiv access to - * the SPI buss. We will retain that exclusive access until the bus is unlocked. - */ - - (void)SPI_LOCK(dev, true); - - /* After locking the SPI bus, the we also need call the setfrequency, setbits, and - * setmode methods to make sure that the SPI is properly configured for the device. - * If the SPI buss is being shared, then it may have been left in an incompatible - * state. - */ - - SPI_SETMODE(dev, SPIDEV_MODE3); - SPI_SETBITS(dev, 8); - - (void)SPI_SETFREQUENCY(dev, RAMTRON_INIT_CLK_MAX); -} - -/************************************************************************************ - * Name: ramtron_unlock - ************************************************************************************/ - -static inline void ramtron_unlock(FAR struct spi_dev_s *dev) -{ - (void)SPI_LOCK(dev, false); -} - -/************************************************************************************ - * Name: ramtron_readid - ************************************************************************************/ - -static inline int ramtron_readid(struct ramtron_dev_s *priv) -{ - uint16_t manufacturer, memory, capacity, part; - int i; - - fvdbg("priv: %p\n", priv); - - /* Lock the SPI bus, configure the bus, and select this FLASH part. */ - - ramtron_lock(priv->dev); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Read ID (RDID)" command and read the first three ID bytes */ - - (void)SPI_SEND(priv->dev, RAMTRON_RDID); - for (i = 0; i < 6; i++) - { - manufacturer = SPI_SEND(priv->dev, RAMTRON_DUMMY); - } - - memory = SPI_SEND(priv->dev, RAMTRON_DUMMY); - capacity = SPI_SEND(priv->dev, RAMTRON_DUMMY); // fram.id1 - part = SPI_SEND(priv->dev, RAMTRON_DUMMY); // fram.id2 - - /* Deselect the FLASH and unlock the bus */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - ramtron_unlock(priv->dev); - - /* Select part from the part list */ - - for (priv->part = ramtron_parts; - priv->part->name != NULL && !(priv->part->id1 == capacity && priv->part->id2 == part); - priv->part++); - - if (priv->part->name) - { - fvdbg("RAMTRON %s of size %d bytes (mf:%02x mem:%02x cap:%02x part:%02x)\n", - priv->part->name, priv->part->size, manufacturer, memory, capacity, part); - - priv->sectorshift = RAMTRON_EMULATE_SECTOR_SHIFT; - priv->nsectors = priv->part->size / (1 << RAMTRON_EMULATE_SECTOR_SHIFT); - priv->pageshift = RAMTRON_EMULATE_PAGE_SHIFT; - priv->npages = priv->part->size / (1 << RAMTRON_EMULATE_PAGE_SHIFT); - return OK; - } - - fvdbg("RAMTRON device not found\n"); - return -ENODEV; -} - -/************************************************************************************ - * Name: ramtron_waitwritecomplete - ************************************************************************************/ - -static void ramtron_waitwritecomplete(struct ramtron_dev_s *priv) -{ - uint8_t status; - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->dev, RAMTRON_RDSR); - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->dev, RAMTRON_DUMMY); - } - while ((status & RAMTRON_SR_WIP) != 0); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Complete\n"); -} - -/************************************************************************************ - * Name: ramtron_writeenable - ************************************************************************************/ - -static void ramtron_writeenable(struct ramtron_dev_s *priv) -{ - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Write Enable (WREN)" command */ - - (void)SPI_SEND(priv->dev, RAMTRON_WREN); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Enabled\n"); -} - -/************************************************************************************ - * Name: ramtron_sendaddr - ************************************************************************************/ - -static inline void ramtron_sendaddr(const struct ramtron_dev_s *priv, uint32_t addr) -{ - DEBUGASSERT(priv->part->addr_len == 3 || priv->part->addr_len == 2); - - if (priv->part->addr_len == 3) - { - (void)SPI_SEND(priv->dev, (addr >> 16) & 0xff); - } - - (void)SPI_SEND(priv->dev, (addr >> 8) & 0xff); - (void)SPI_SEND(priv->dev, addr & 0xff); -} - -/************************************************************************************ - * Name: ramtron_pagewrite - ************************************************************************************/ - -static inline void ramtron_pagewrite(struct ramtron_dev_s *priv, FAR const uint8_t *buffer, - off_t page) -{ - off_t offset = page << priv->pageshift; - - fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - ramtron_waitwritecomplete(priv); - - /* Enable the write access to the FLASH */ - - ramtron_writeenable(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Page Program (PP)" command */ - - (void)SPI_SEND(priv->dev, RAMTRON_WRITE); - - /* Send the page offset high byte first. */ - - ramtron_sendaddr(priv, offset); - - /* Then write the specified number of bytes */ - - SPI_SNDBLOCK(priv->dev, buffer, 1 << priv->pageshift); - - /* Deselect the FLASH: Chip Select high */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Written\n"); -} - -/************************************************************************************ - * Name: ramtron_erase - ************************************************************************************/ - -static int ramtron_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - fvdbg("On RAMTRON devices erasing makes no sense, returning as OK\n"); - return (int)nblocks; -} - -/************************************************************************************ - * Name: ramtron_bread - ************************************************************************************/ - -static ssize_t ramtron_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buffer) -{ - FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev; - ssize_t nbytes; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* On this device, we can handle the block read just like the byte-oriented read */ - - nbytes = ramtron_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer); - if (nbytes > 0) - { - return nbytes >> priv->pageshift; - } - - return (int)nbytes; -} - -/************************************************************************************ - * Name: ramtron_bwrite - ************************************************************************************/ - -static ssize_t ramtron_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) -{ - FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev; - size_t blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock the SPI bus and write each page to FLASH */ - - ramtron_lock(priv->dev); - while (blocksleft-- > 0) - { - ramtron_pagewrite(priv, buffer, startblock); - startblock++; - } - - ramtron_unlock(priv->dev); - return nblocks; -} - -/************************************************************************************ - * Name: ramtron_read - ************************************************************************************/ - -static ssize_t ramtron_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer) -{ - FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev; - - fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); - - /* Wait for any preceding write to complete. We could simplify things by - * perform this wait at the end of each write operation (rather than at - * the beginning of ALL operations), but have the wait first will slightly - * improve performance. - */ - - ramtron_waitwritecomplete(priv); - - /* Lock the SPI bus and select this FLASH part */ - - ramtron_lock(priv->dev); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read from Memory " instruction */ - - (void)SPI_SEND(priv->dev, RAMTRON_READ); - - /* Send the page offset high byte first. */ - - ramtron_sendaddr(priv, offset); - - /* Then read all of the requested bytes */ - - SPI_RECVBLOCK(priv->dev, buffer, nbytes); - - /* Deselect the FLASH and unlock the SPI bus */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - ramtron_unlock(priv->dev); - fvdbg("return nbytes: %d\n", (int)nbytes); - return nbytes; -} - -/************************************************************************************ - * Name: ramtron_ioctl - ************************************************************************************/ - -static int ramtron_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct ramtron_dev_s *priv = (FAR struct ramtron_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - fvdbg("cmd: %d \n", cmd); - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - */ - - geo->blocksize = (1 << priv->pageshift); - geo->erasesize = (1 << priv->sectorshift); - geo->neraseblocks = priv->nsectors; - ret = OK; - - fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); - } - } - break; - - case MTDIOC_BULKERASE: - fvdbg("BULDERASE: Makes no sense in ramtron. Let's confirm operation as OK\n"); - ret = OK; - break; - - case MTDIOC_XIPBASE: - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - fvdbg("return %d\n", ret); - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: ramtron_initialize - * - * Description: - * Create an initialize MTD device instance. MTD devices are not registered - * in the file system, but are created as instances that can be bound to - * other functions (such as a block or character driver front end). - * - ************************************************************************************/ - -FAR struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *dev) -{ - FAR struct ramtron_dev_s *priv; - - fvdbg("dev: %p\n", dev); - - /* Allocate a state structure (we allocate the structure instead of using - * a fixed, static allocation so that we can handle multiple FLASH devices. - * The current implementation would handle only one FLASH part per SPI - * device (only because of the SPIDEV_FLASH definition) and so would have - * to be extended to handle multiple FLASH parts on the same SPI bus. - */ - - priv = (FAR struct ramtron_dev_s *)kmalloc(sizeof(struct ramtron_dev_s)); - if (priv) - { - /* Initialize the allocated structure */ - - priv->mtd.erase = ramtron_erase; - priv->mtd.bread = ramtron_bread; - priv->mtd.bwrite = ramtron_bwrite; - priv->mtd.read = ramtron_read; - priv->mtd.ioctl = ramtron_ioctl; - priv->dev = dev; - - /* Deselect the FLASH */ - - SPI_SELECT(dev, SPIDEV_FLASH, false); - - /* Identify the FLASH chip and get its capacity */ - - if (ramtron_readid(priv) != OK) - { - /* Unrecognized! Discard all of that work we just did and return NULL */ - - kfree(priv); - priv = NULL; - } - } - - /* Return the implementation-specific state structure as the MTD device */ - - fvdbg("Return %p\n", priv); - return (FAR struct mtd_dev_s *)priv; -} diff --git a/nuttx/drivers/mtd/skeleton.c b/nuttx/drivers/mtd/skeleton.c deleted file mode 100644 index a2fb98238..000000000 --- a/nuttx/drivers/mtd/skeleton.c +++ /dev/null @@ -1,275 +0,0 @@ -/**************************************************************************** - * drivers/mtd/skeleton.c - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s - * must appear at the beginning of the definition so that you can freely - * cast between pointers to struct mtd_dev_s and struct skel_dev_s. - */ - -struct skel_dev_s -{ - struct mtd_dev_s mtd; - - /* Other implementation specific data may follow here */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* MTD driver methods */ - -static int skel_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t skel_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buf); -static ssize_t skel_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buf); -static ssize_t skel_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct skel_dev_s g_skeldev = -{ - { skel_erase, skel_rbead, skel_bwrite, skel_read, skel_ioctl }, - /* Initialization of any other implemenation specific data goes here */ -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: skel_erase - ****************************************************************************/ - -static int skel_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ - FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; - - /* The interface definition assumes that all erase blocks ar the same size. - * If that is not true for this particular device, then transform the - * start block and nblocks as necessary. - */ - - /* Erase the specified blocks and return status (OK or a negated errno) */ - - return OK; -} - -/**************************************************************************** - * Name: skel_bread - ****************************************************************************/ - -static ssize_t skel_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buf) -{ - FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; - - /* The interface definition assumes that all read/write blocks ar the same size. - * If that is not true for this particular device, then transform the - * start block and nblocks as necessary. - */ - - /* Read the specified blocks into the provided user buffer and return status - * (The positive, number of blocks actually read or a negated errno). - */ - - return 0; -} - -/**************************************************************************** - * Name: skel_bwrite - ****************************************************************************/ - -static ssize_t skel_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buf) -{ - FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; - - /* The interface definition assumes that all read/write blocks ar the same size. - * If that is not true for this particular device, then transform the - * start block and nblocks as necessary. - */ - - /* Write the specified blocks from the provided user buffer and return status - * (The positive, number of blocks actually written or a negated errno) - */ - - return 0; -} - -/**************************************************************************** - * Name: skel_read - ****************************************************************************/ - -static ssize_t skel_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer) -{ - FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; - - /* Some devices may support byte oriented read (optional). Byte-oriented - * writing is inherently block oriented on most MTD devices and is not supported. - * It is recommended that low-level drivers not support read() if it requires - * buffering -- let the higher level logic handle that. If the read method is - * not implemented, just set the method pointer to NULL in the struct mtd_dev_s - * instance. - */ - - /* The interface definition assumes that all read/write blocks ar the same size. - * If that is not true for this particular device, then transform the - * start block and nblocks as necessary. - */ - - /* Read the specified blocks into the provided user buffer and return status - * (The positive, number of blocks actually read or a negated errno) - */ - - return 0; -} - -/**************************************************************************** - * Name: skel_ioctl - ****************************************************************************/ - -static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FARstruct mtd_geometry_s *)arg; - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - */ - - geo->blocksize = 512; /* Size of one read/write block */ - geo->erasesize = 4096; /* Size of one erase block */ - geo->neraseblocks = 1024; /* Number of erase blocks */ - ret = OK; - } - } - break; - - case MTDIOC_XIPBASE: - { - FAR void **ppv = (FAR void**)arg; - - if (ppv) - { - /* If media is directly acccesible, return (void*) base address - * of device memory. NULL otherwise. It is acceptable to omit - * this case altogether and simply return -ENOTTY. - */ - - *ppv = NULL; - ret = OK; - } - } - break; - - case MTDIOC_BULKERASE: - { - /* Erase the entire device */ - - ret = OK; - } - break; - - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: skel_initialize - * - * Description: - * Create and initialize an MTD device instance. MTD devices are not - * registered in the file system, but are created as instances that can - * be bound to other functions (such as a block or character driver front - * end). - * - ****************************************************************************/ - -void skel_initialize(void) -{ - /* Perform initialization as necessary */ - - /* Return the implementation-specific state structure as the MTD device */ - - return (FAR struct mtd_dev_s *)&g_skeldev; -} diff --git a/nuttx/drivers/mtd/sst25.c b/nuttx/drivers/mtd/sst25.c deleted file mode 100644 index 66d201add..000000000 --- a/nuttx/drivers/mtd/sst25.c +++ /dev/null @@ -1,1250 +0,0 @@ -/************************************************************************************ - * drivers/mtd/sst25.c - * Driver for SPI-based SST25 FLASH. - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ -/* Configuration ********************************************************************/ -/* Per the data sheet, the SST25 parts can be driven with either SPI mode 0 (CPOL=0 - * and CPHA=0) or mode 3 (CPOL=1 and CPHA=1). But I have heard that other devices - * can operate in mode 0 or 1. So you may need to specify CONFIG_SST25_SPIMODE to - * select the best mode for your device. If CONFIG_SST25_SPIMODE is not defined, - * mode 0 will be used. - */ - -#ifndef CONFIG_SST25_SPIMODE -# define CONFIG_SST25_SPIMODE SPIDEV_MODE0 -#endif - -/* SPI Frequency. May be up to 25MHz. */ - -#ifndef CONFIG_SST25_SPIFREQUENCY -# define CONFIG_SST25_SPIFREQUENCY 20000000 -#endif - -/* There is a bug in the current code when using the higher speed AAI write sequence. - * The nature of the bug is that the WRDI instruction is not working. At the end - * of the AAI sequence, the status register continues to report that the SST25 is - * write enabled (WEL bit) and in AAI mode (AAI bit). This *must* be fixed in any - * production code if you want to have proper write performance. - */ - -#warning "REVISIT" -#undef CONFIG_SST25_SLOWWRITE -#define CONFIG_SST25_SLOWWRITE 1 - -/* SST25 Instructions ***************************************************************/ -/* Command Value Description Addr Data */ -/* Dummy */ -#define SST25_READ 0x03 /* Read data bytes 3 0 >=1 */ -#define SST25_FAST_READ 0x0b /* Higher speed read 3 1 >=1 */ -#define SST25_SE 0x20 /* 4Kb Sector erase 3 0 0 */ -#define SST25_BE32 0x52 /* 32Kbit block Erase 3 0 0 */ -#define SST25_BE64 0xd8 /* 64Kbit block Erase 3 0 0 */ -#define SST25_CE 0xc7 /* Chip erase 0 0 0 */ -#define SST25_CE_ALT 0x60 /* Chip erase (alternate) 0 0 0 */ -#define SST25_BP 0x02 /* Byte program 3 0 1 */ -#define SST25_AAI 0xad /* Auto address increment 3 0 >=2 */ -#define SST25_RDSR 0x05 /* Read status register 0 0 >=1 */ -#define SST25_EWSR 0x50 /* Write enable status 0 0 0 */ -#define SST25_WRSR 0x01 /* Write Status Register 0 0 1 */ -#define SST25_WREN 0x06 /* Write Enable 0 0 0 */ -#define SST25_WRDI 0x04 /* Write Disable 0 0 0 */ -#define SST25_RDID 0xab /* Read Identification 0 0 >=1 */ -#define SST25_RDID_ALT 0x90 /* Read Identification (alt) 0 0 >=1 */ -#define SST25_JEDEC_ID 0x9f /* JEDEC ID read 0 0 >=3 */ -#define SST25_EBSY 0x70 /* Enable SO RY/BY# status 0 0 0 */ -#define SST25_DBSY 0x80 /* Disable SO RY/BY# status 0 0 0 */ - -/* SST25 Registers ******************************************************************/ -/* Read ID (RDID) register values */ - -#define SST25_MANUFACTURER 0xbf /* SST manufacturer ID */ -#define SST25_VF032_DEVID 0x20 /* SSTVF032B device ID */ - -/* JEDEC Read ID register values */ - -#define SST25_JEDEC_MANUFACTURER 0xbf /* SST manufacturer ID */ -#define SST25_JEDEC_MEMORY_TYPE 0x25 /* SST25 memory type */ -#define SST25_JEDEC_MEMORY_CAPACITY 0x4a /* SST25VF032B memory capacity */ - -/* Status register bit definitions */ - -#define SST25_SR_BUSY (1 << 0) /* Bit 0: Write in progress */ -#define SST25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */ -#define SST25_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */ -#define SST25_SR_BP_MASK (15 << SST25_SR_BP_SHIFT) -# define SST25_SR_BP_NONE (0 << SST25_SR_BP_SHIFT) /* Unprotected */ -# define SST25_SR_BP_UPPER64th (1 << SST25_SR_BP_SHIFT) /* Upper 64th */ -# define SST25_SR_BP_UPPER32nd (2 << SST25_SR_BP_SHIFT) /* Upper 32nd */ -# define SST25_SR_BP_UPPER16th (3 << SST25_SR_BP_SHIFT) /* Upper 16th */ -# define SST25_SR_BP_UPPER8th (4 << SST25_SR_BP_SHIFT) /* Upper 8th */ -# define SST25_SR_BP_UPPERQTR (5 << SST25_SR_BP_SHIFT) /* Upper quarter */ -# define SST25_SR_BP_UPPERHALF (6 << SST25_SR_BP_SHIFT) /* Upper half */ -# define SST25_SR_BP_ALL (7 << SST25_SR_BP_SHIFT) /* All sectors */ -#define SST25_SR_AAI (1 << 6) /* Bit 6: Auto Address increment programming */ -#define SST25_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */ - -#define SST25_DUMMY 0xa5 - -/* Chip Geometries ******************************************************************/ -/* SST25VF512 capacity is 512Kbit (64Kbit x 8) = 64Kb (8Kb x 8)*/ -/* SST25VF010 capacity is 1Mbit (128Kbit x 8) = 128Kb (16Kb x 8*/ -/* SST25VF520 capacity is 2Mbit (256Kbit x 8) = 256Kb (32Kb x 8) */ -/* SST25VF540 capacity is 4Mbit (512Kbit x 8) = 512Kb (64Kb x 8) */ -/* SST25VF080 capacity is 8Mbit (1024Kbit x 8) = 1Mb (128Kb x 8) */ -/* SST25VF016 capacity is 16Mbit (2048Kbit x 8) = 2Mb (256Kb x 8) */ -/* Not yet supported */ - -/* SST25VF032 capacity is 32Mbit (4096Kbit x 8) = 4Mb (512kb x 8) */ - -#define SST25_VF032_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4Kb */ -#define SST25_VF032_NSECTORS 1024 /* 1024 sectors x 4096 bytes/sector = 4Mb */ - -#ifdef CONFIG_SST25_SECTOR512 /* Simulate a 512 byte sector */ -# define SST25_SECTOR_SHIFT 9 /* Sector size 1 << 9 = 512 bytes */ -# define SST25_SECTOR_SIZE 512 /* Sector size = 512 bytes */ -#endif - -#define SST25_ERASED_STATE 0xff /* State of FLASH when erased */ - -/* Cache flags */ - -#define SST25_CACHE_VALID (1 << 0) /* 1=Cache has valid data */ -#define SST25_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */ -#define SST25_CACHE_ERASED (1 << 2) /* 1=Backing FLASH is erased */ - -#define IS_VALID(p) ((((p)->flags) & SST25_CACHE_VALID) != 0) -#define IS_DIRTY(p) ((((p)->flags) & SST25_CACHE_DIRTY) != 0) -#define IS_ERASED(p) ((((p)->flags) & SST25_CACHE_DIRTY) != 0) - -#define SET_VALID(p) do { (p)->flags |= SST25_CACHE_VALID; } while (0) -#define SET_DIRTY(p) do { (p)->flags |= SST25_CACHE_DIRTY; } while (0) -#define SET_ERASED(p) do { (p)->flags |= SST25_CACHE_DIRTY; } while (0) - -#define CLR_VALID(p) do { (p)->flags &= ~SST25_CACHE_VALID; } while (0) -#define CLR_DIRTY(p) do { (p)->flags &= ~SST25_CACHE_DIRTY; } while (0) -#define CLR_ERASED(p) do { (p)->flags &= ~SST25_CACHE_DIRTY; } while (0) - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s must - * appear at the beginning of the definition so that you can freely cast between - * pointers to struct mtd_dev_s and struct sst25_dev_s. - */ - -struct sst25_dev_s -{ - struct mtd_dev_s mtd; /* MTD interface */ - FAR struct spi_dev_s *dev; /* Saved SPI interface instance */ - uint16_t nsectors; /* Number of erase sectors */ - uint8_t sectorshift; /* Log2 of erase sector size */ - -#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY) - uint8_t flags; /* Buffered sector flags */ - uint16_t esectno; /* Erase sector number in the cache*/ - FAR uint8_t *sector; /* Allocated sector data */ -#endif -}; - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/* Helpers */ - -static void sst25_lock(FAR struct spi_dev_s *dev); -static inline void sst25_unlock(FAR struct spi_dev_s *dev); -static inline int sst25_readid(FAR struct sst25_dev_s *priv); -#ifndef CONFIG_SST25_READONLY -static void sst25_unprotect(FAR struct spi_dev_s *dev); -#endif -static uint8_t sst25_waitwritecomplete(FAR struct sst25_dev_s *priv); -static inline void sst25_wren(FAR struct sst25_dev_s *priv); -static inline void sst25_wrdi(FAR struct sst25_dev_s *priv); -static void sst25_sectorerase(FAR struct sst25_dev_s *priv, off_t offset); -static inline int sst25_chiperase(FAR struct sst25_dev_s *priv); -static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer, - off_t address, size_t nbytes); -#ifndef CONFIG_SST25_READONLY -#ifdef CONFIG_SST25_SLOWWRITE -static void sst25_bytewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer, - off_t address, size_t nbytes); -#else -static void sst25_wordwrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer, - off_t address, size_t nbytes); -#endif -#ifdef CONFIG_SST25_SECTOR512 -static void sst25_cacheflush(struct sst25_dev_s *priv); -static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector); -static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector); -static void sst25_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer, - off_t sector, size_t nsectors); -#endif -#endif - -/* MTD driver methods */ - -static int sst25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buf); -static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); -static ssize_t sst25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int sst25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: sst25_lock - ************************************************************************************/ - -static void sst25_lock(FAR struct spi_dev_s *dev) -{ - /* On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of - * transfers. The bus should be locked before the chip is selected. - * - * This is a blocking call and will not return until we have exclusiv access to - * the SPI buss. We will retain that exclusive access until the bus is unlocked. - */ - - (void)SPI_LOCK(dev, true); - - /* After locking the SPI bus, the we also need call the setfrequency, setbits, and - * setmode methods to make sure that the SPI is properly configured for the device. - * If the SPI buss is being shared, then it may have been left in an incompatible - * state. - */ - - SPI_SETMODE(dev, CONFIG_SST25_SPIMODE); - SPI_SETBITS(dev, 8); - (void)SPI_SETFREQUENCY(dev, CONFIG_SST25_SPIFREQUENCY); -} - -/************************************************************************************ - * Name: sst25_unlock - ************************************************************************************/ - -static inline void sst25_unlock(FAR struct spi_dev_s *dev) -{ - (void)SPI_LOCK(dev, false); -} - -/************************************************************************************ - * Name: sst25_readid - ************************************************************************************/ - -static inline int sst25_readid(struct sst25_dev_s *priv) -{ - uint16_t manufacturer; - uint16_t memory; - uint16_t capacity; - - fvdbg("priv: %p\n", priv); - - /* Lock the SPI bus, configure the bus, and select this FLASH part. */ - - sst25_lock(priv->dev); - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Read ID (RDID)" command and read the first three ID bytes */ - - (void)SPI_SEND(priv->dev, SST25_JEDEC_ID); - manufacturer = SPI_SEND(priv->dev, SST25_DUMMY); - memory = SPI_SEND(priv->dev, SST25_DUMMY); - capacity = SPI_SEND(priv->dev, SST25_DUMMY); - - /* Deselect the FLASH and unlock the bus */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - sst25_unlock(priv->dev); - - fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n", - manufacturer, memory, capacity); - - /* Check for a valid manufacturer and memory type */ - - if (manufacturer == SST25_JEDEC_MANUFACTURER && memory == SST25_JEDEC_MEMORY_TYPE) - { - /* Okay.. is it a FLASH capacity that we understand? This should be extended - * support other members of the SST25 family. - */ - - if (capacity == SST25_JEDEC_MEMORY_CAPACITY) - { - /* Save the FLASH geometry */ - - priv->sectorshift = SST25_VF032_SECTOR_SHIFT; - priv->nsectors = SST25_VF032_NSECTORS; - return OK; - } - } - - return -ENODEV; -} - -/************************************************************************************ - * Name: sst25_unprotect - ************************************************************************************/ - -#ifndef CONFIG_SST25_READONLY -static void sst25_unprotect(FAR struct spi_dev_s *dev) -{ - /* Select this FLASH part */ - - SPI_SELECT(dev, SPIDEV_FLASH, true); - - /* Send "Write enable status (EWSR)" */ - - SPI_SEND(dev, SST25_EWSR); - - /* Re-select this FLASH part (This might not be necessary... but is it shown in - * the timing diagrams) - */ - - SPI_SELECT(dev, SPIDEV_FLASH, false); - SPI_SELECT(dev, SPIDEV_FLASH, true); - - /* Send "Write enable status (EWSR)" */ - - SPI_SEND(dev, SST25_WRSR); - - /* Following by the new status value */ - - SPI_SEND(dev, 0); -} -#endif - -/************************************************************************************ - * Name: sst25_waitwritecomplete - ************************************************************************************/ - -static uint8_t sst25_waitwritecomplete(struct sst25_dev_s *priv) -{ - uint8_t status; - - /* Are we the only device on the bus? */ - -#ifdef CONFIG_SPI_OWNBUS - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->dev, SST25_RDSR); - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->dev, SST25_DUMMY); - } - while ((status & SST25_SR_BUSY) != 0); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - -#else - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->dev, SST25_RDSR); - - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->dev, SST25_DUMMY); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - - /* Given that writing could take up to few tens of milliseconds, and erasing - * could take more. The following short delay in the "busy" case will allow - * other peripherals to access the SPI bus. - */ - -#if 0 /* Makes writes too slow */ - if ((status & SST25_SR_BUSY) != 0) - { - sst25_unlock(priv->dev); - usleep(1000); - sst25_lock(priv->dev); - } -#endif - } - while ((status & SST25_SR_BUSY) != 0); -#endif - - return status; -} - -/************************************************************************************ - * Name: sst25_wren - ************************************************************************************/ - -static inline void sst25_wren(struct sst25_dev_s *priv) -{ - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Write Enable (WREN)" command */ - - (void)SPI_SEND(priv->dev, SST25_WREN); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: sst25_wrdi - ************************************************************************************/ - -static inline void sst25_wrdi(struct sst25_dev_s *priv) -{ - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Write Disable (WRDI)" command */ - - (void)SPI_SEND(priv->dev, SST25_WRDI); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: sst25_sectorerase - ************************************************************************************/ - -static void sst25_sectorerase(struct sst25_dev_s *priv, off_t sector) -{ - off_t address = sector << priv->sectorshift; - - fvdbg("sector: %08lx\n", (long)sector); - - /* Wait for any preceding write or erase operation to complete. */ - - (void)sst25_waitwritecomplete(priv); - - /* Send write enable instruction */ - - sst25_wren(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Sector Erase (SE)" instruction */ - - (void)SPI_SEND(priv->dev, SST25_SE); - - /* Send the sector address high byte first. Only the most significant bits (those - * corresponding to the sector) have any meaning. - */ - - (void)SPI_SEND(priv->dev, (address >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (address >> 8) & 0xff); - (void)SPI_SEND(priv->dev, address & 0xff); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: sst25_chiperase - ************************************************************************************/ - -static inline int sst25_chiperase(struct sst25_dev_s *priv) -{ - fvdbg("priv: %p\n", priv); - - /* Wait for any preceding write or erase operation to complete. */ - - (void)sst25_waitwritecomplete(priv); - - /* Send write enable instruction */ - - sst25_wren(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send the "Chip Erase (CE)" instruction */ - - (void)SPI_SEND(priv->dev, SST25_CE); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - fvdbg("Return: OK\n"); - return OK; -} - -/************************************************************************************ - * Name: sst25_byteread - ************************************************************************************/ - -static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer, - off_t address, size_t nbytes) -{ - uint8_t status; - - fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes); - - /* Wait for any preceding write or erase operation to complete. */ - - status = sst25_waitwritecomplete(priv); - DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Read from Memory " instruction */ - -#ifdef CONFIG_SST25_SLOWREAD - (void)SPI_SEND(priv->dev, SST25_READ); -#else - (void)SPI_SEND(priv->dev, SST25_FAST_READ); -#endif - - /* Send the address high byte first. */ - - (void)SPI_SEND(priv->dev, (address >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (address >> 8) & 0xff); - (void)SPI_SEND(priv->dev, address & 0xff); - - /* Send a dummy byte */ - -#ifndef CONFIG_SST25_SLOWREAD - (void)SPI_SEND(priv->dev, SST25_DUMMY); -#endif - - /* Then read all of the requested bytes */ - - SPI_RECVBLOCK(priv->dev, buffer, nbytes); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: sst25_bytewrite - ************************************************************************************/ - -#if defined(CONFIG_SST25_SLOWWRITE) && !defined(CONFIG_SST25_READONLY) -static void sst25_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer, - off_t address, size_t nbytes) -{ - uint8_t status; - - fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nbytes); - DEBUGASSERT(priv && buffer); - - /* Write each byte individually */ - - for (; nbytes > 0; nbytes--) - { - /* Skip over bytes that are begin written to the erased state */ - - if (*buffer != SST25_ERASED_STATE) - { - /* Wait for any preceding write or erase operation to complete. */ - - status = sst25_waitwritecomplete(priv); - DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0); - - /* Enable write access to the FLASH */ - - sst25_wren(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Byte Program (BP)" command */ - - (void)SPI_SEND(priv->dev, SST25_BP); - - /* Send the byte address high byte first. */ - - (void)SPI_SEND(priv->dev, (address >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (address >> 8) & 0xff); - (void)SPI_SEND(priv->dev, address & 0xff); - - /* Then write the single byte */ - - (void)SPI_SEND(priv->dev, *buffer); - - /* Deselect the FLASH and setup for the next pass through the loop */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - } - - /* Advance to the next byte */ - - buffer++; - address++; - } -} -#endif - -/************************************************************************************ - * Name: sst25_wordwrite - ************************************************************************************/ - -#if !defined(CONFIG_SST25_SLOWWRITE) && !defined(CONFIG_SST25_READONLY) -static void sst25_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer, - off_t address, size_t nbytes) -{ - size_t nwords = (nbytes + 1) >> 1; - uint8_t status; - - fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nwords); - DEBUGASSERT(priv && buffer); - - /* Loop until all of the bytes have been written */ - - while (nwords > 0) - { - /* Skip over any data that is being written to the erased state */ - - while (nwords > 0 && - buffer[0] == SST25_ERASED_STATE && - buffer[1] == SST25_ERASED_STATE) - { - /* Decrement the word count and advance the write position */ - - nwords--; - buffer += 2; - address += 2; - } - - /* If there are no further non-erased bytes in the user buffer, then - * we are finished. - */ - - if (nwords <= 0) - { - return; - } - - /* Wait for any preceding write or erase operation to complete. */ - - status = sst25_waitwritecomplete(priv); - DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0); - - /* Enable write access to the FLASH */ - - sst25_wren(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Auto Address Increment (AAI)" command */ - - (void)SPI_SEND(priv->dev, SST25_AAI); - - /* Send the word address high byte first. */ - - (void)SPI_SEND(priv->dev, (address >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (address >> 8) & 0xff); - (void)SPI_SEND(priv->dev, address & 0xff); - - /* Then write one 16-bit word */ - - SPI_SNDBLOCK(priv->dev, buffer, 2); - - /* Deselect the FLASH: Chip Select high */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - - /* Decrement the word count and advance the write position */ - - nwords--; - buffer += 2; - address += 2; - - /* Now loop, writing 16-bits of data on each pass through the loop - * until all of the words have been transferred or until we encounter - * data to be written to the erased state. - */ - - while (nwords > 0 && - (buffer[0] != SST25_ERASED_STATE || - buffer[1] != SST25_ERASED_STATE)) - { - /* Wait for the preceding write to complete. */ - - status = sst25_waitwritecomplete(priv); - DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == (SST25_SR_WEL|SST25_SR_AAI)); - - /* Select this FLASH part */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, true); - - /* Send "Auto Address Increment (AAI)" command with no address */ - - (void)SPI_SEND(priv->dev, SST25_AAI); - - /* Then write one 16-bit word */ - - SPI_SNDBLOCK(priv->dev, buffer, 2); - - /* Deselect the FLASH: Chip Select high */ - - SPI_SELECT(priv->dev, SPIDEV_FLASH, false); - - /* Decrement the word count and advance the write position */ - - nwords--; - buffer += 2; - address += 2; - } - - /* Disable writing */ - - sst25_wrdi(priv); - } -} -#endif - -/************************************************************************************ - * Name: sst25_cacheflush - ************************************************************************************/ - -#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY) -static void sst25_cacheflush(struct sst25_dev_s *priv) -{ - /* If the cached is dirty (meaning that it no longer matches the old FLASH contents) - * or was erased (with the cache containing the correct FLASH contents), then write - * the cached erase block to FLASH. - */ - - if (IS_DIRTY(priv) || IS_ERASED(priv)) - { - /* Write entire erase block to FLASH */ - -#ifdef CONFIG_SST25_SLOWWRITE - sst25_bytewrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift, - (1 << priv->sectorshift)); -#else - sst25_wordwrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift, - (1 << priv->sectorshift)); -#endif - - /* The case is no long dirty and the FLASH is no longer erased */ - - CLR_DIRTY(priv); - CLR_ERASED(priv); - } -} -#endif - -/************************************************************************************ - * Name: sst25_cacheread - ************************************************************************************/ - -#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY) -static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector) -{ - off_t esectno; - int shift; - int index; - - /* Convert from the 512 byte sector to the erase sector size of the device. For - * exmample, if the actual erase sector size if 4Kb (1 << 12), then we first - * shift to the right by 3 to get the sector number in 4096 increments. - */ - - shift = priv->sectorshift - SST25_SECTOR_SHIFT; - esectno = sector >> shift; - fvdbg("sector: %ld esectno: %d shift=%d\n", sector, esectno, shift); - - /* Check if the requested erase block is already in the cache */ - - if (!IS_VALID(priv) || esectno != priv->esectno) - { - /* No.. Flush any dirty erase block currently in the cache */ - - sst25_cacheflush(priv); - - /* Read the erase block into the cache */ - - sst25_byteread(priv, priv->sector, (esectno << priv->sectorshift), 1 << priv->sectorshift); - - /* Mark the sector as cached */ - - priv->esectno = esectno; - - SET_VALID(priv); /* The data in the cache is valid */ - CLR_DIRTY(priv); /* It should match the FLASH contents */ - CLR_ERASED(priv); /* The underlying FLASH has not been erased */ - } - - /* Get the index to the 512 sector in the erase block that holds the argument */ - - index = sector & ((1 << shift) - 1); - - /* Return the address in the cache that holds this sector */ - - return &priv->sector[index << SST25_SECTOR_SHIFT]; -} -#endif - -/************************************************************************************ - * Name: sst25_cacheerase - ************************************************************************************/ - -#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY) -static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector) -{ - FAR uint8_t *dest; - - /* First, make sure that the erase block containing the 512 byte sector is in - * the cache. - */ - - dest = sst25_cacheread(priv, sector); - - /* Erase the block containing this sector if it is not already erased. - * The erased indicated will be cleared when the data from the erase sector - * is read into the cache and set here when we erase the block. - */ - - if (!IS_ERASED(priv)) - { - off_t esectno = sector >> (priv->sectorshift - SST25_SECTOR_SHIFT); - fvdbg("sector: %ld esectno: %d\n", sector, esectno); - - sst25_sectorerase(priv, esectno); - SET_ERASED(priv); - } - - /* Put the cached sector data into the erase state and mart the cache as dirty - * (but don't update the FLASH yet. The caller will do that at a more optimal - * time). - */ - - memset(dest, SST25_ERASED_STATE, SST25_SECTOR_SIZE); - SET_DIRTY(priv); -} -#endif - -/************************************************************************************ - * Name: sst25_cachewrite - ************************************************************************************/ - -#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY) -static void sst25_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer, - off_t sector, size_t nsectors) -{ - FAR uint8_t *dest; - - for (; nsectors > 0; nsectors--) - { - /* First, make sure that the erase block containing 512 byte sector is in - * memory. - */ - - dest = sst25_cacheread(priv, sector); - - /* Erase the block containing this sector if it is not already erased. - * The erased indicated will be cleared when the data from the erase sector - * is read into the cache and set here when we erase the sector. - */ - - if (!IS_ERASED(priv)) - { - off_t esectno = sector >> (priv->sectorshift - SST25_SECTOR_SHIFT); - fvdbg("sector: %ld esectno: %d\n", sector, esectno); - - sst25_sectorerase(priv, esectno); - SET_ERASED(priv); - } - - /* Copy the new sector data into cached erase block */ - - memcpy(dest, buffer, SST25_SECTOR_SIZE); - SET_DIRTY(priv); - - /* Set up for the next 512 byte sector */ - - buffer += SST25_SECTOR_SIZE; - sector++; - } - - /* Flush the last erase block left in the cache */ - - sst25_cacheflush(priv); -} -#endif - -/************************************************************************************ - * Name: sst25_erase - ************************************************************************************/ - -static int sst25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ -#ifdef CONFIG_SST25_READONLY - return -EACESS -#else - FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev; - size_t blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock access to the SPI bus until we complete the erase */ - - sst25_lock(priv->dev); - - while (blocksleft-- > 0) - { - /* Erase each sector */ - -#ifdef CONFIG_SST25_SECTOR512 - sst25_cacheerase(priv, startblock); -#else - sst25_sectorerase(priv, startblock); -#endif - startblock++; - } - -#ifdef CONFIG_SST25_SECTOR512 - /* Flush the last erase block left in the cache */ - - sst25_cacheflush(priv); -#endif - - sst25_unlock(priv->dev); - return (int)nblocks; -#endif -} - -/************************************************************************************ - * Name: sst25_bread - ************************************************************************************/ - -static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buffer) -{ -#ifdef CONFIG_SST25_SECTOR512 - ssize_t nbytes; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* On this device, we can handle the block read just like the byte-oriented read */ - - nbytes = sst25_read(dev, startblock << SST25_SECTOR_SHIFT, nblocks << SST25_SECTOR_SHIFT, buffer); - if (nbytes > 0) - { - return nbytes >> SST25_SECTOR_SHIFT; - } - - return (int)nbytes; -#else - FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev; - ssize_t nbytes; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* On this device, we can handle the block read just like the byte-oriented read */ - - nbytes = sst25_read(dev, startblock << priv->sectorshift, nblocks << priv->sectorshift, buffer); - if (nbytes > 0) - { - return nbytes >> priv->sectorshift; - } - - return (int)nbytes; -#endif -} - -/************************************************************************************ - * Name: sst25_bwrite - ************************************************************************************/ - -static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) -{ -#ifdef CONFIG_SST25_READONLY - return -EACCESS; -#else - FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock the SPI bus and write all of the pages to FLASH */ - - sst25_lock(priv->dev); - -#if defined(CONFIG_SST25_SECTOR512) - sst25_cachewrite(priv, buffer, startblock, nblocks); -#elif defined(CONFIG_SST25_SLOWWRITE) - sst25_bytewrite(priv, buffer, startblock << priv->sectorshift, - nblocks << priv->sectorshift); -#else - sst25_wordwrite(priv, buffer, startblock << priv->sectorshift, - nblocks << priv->sectorshift); -#endif - sst25_unlock(priv->dev); - - return nblocks; -#endif -} - -/************************************************************************************ - * Name: sst25_read - ************************************************************************************/ - -static ssize_t sst25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer) -{ - FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev; - - fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); - - /* Lock the SPI bus and select this FLASH part */ - - sst25_lock(priv->dev); - sst25_byteread(priv, buffer, offset, nbytes); - sst25_unlock(priv->dev); - - fvdbg("return nbytes: %d\n", (int)nbytes); - return nbytes; -} - -/************************************************************************************ - * Name: sst25_ioctl - ************************************************************************************/ - -static int sst25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - fvdbg("cmd: %d \n", cmd); - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - */ - -#ifdef CONFIG_SST25_SECTOR512 - geo->blocksize = (1 << SST25_SECTOR_SHIFT); - geo->erasesize = (1 << SST25_SECTOR_SHIFT); - geo->neraseblocks = priv->nsectors << (priv->sectorshift - ); -#else - geo->blocksize = (1 << priv->sectorshift); - geo->erasesize = (1 << priv->sectorshift); - geo->neraseblocks = priv->nsectors; -#endif - ret = OK; - - fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); - } - } - break; - - case MTDIOC_BULKERASE: - { - /* Erase the entire device */ - - sst25_lock(priv->dev); - ret = sst25_chiperase(priv); - sst25_unlock(priv->dev); - } - break; - - case MTDIOC_XIPBASE: - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - fvdbg("return %d\n", ret); - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: sst25_initialize - * - * Description: - * Create an initialize MTD device instance. MTD devices are not registered - * in the file system, but are created as instances that can be bound to - * other functions (such as a block or character driver front end). - * - ************************************************************************************/ - -FAR struct mtd_dev_s *sst25_initialize(FAR struct spi_dev_s *dev) -{ - FAR struct sst25_dev_s *priv; - int ret; - - fvdbg("dev: %p\n", dev); - - /* Allocate a state structure (we allocate the structure instead of using - * a fixed, static allocation so that we can handle multiple FLASH devices. - * The current implementation would handle only one FLASH part per SPI - * device (only because of the SPIDEV_FLASH definition) and so would have - * to be extended to handle multiple FLASH parts on the same SPI bus. - */ - - priv = (FAR struct sst25_dev_s *)kzalloc(sizeof(struct sst25_dev_s)); - if (priv) - { - /* Initialize the allocated structure */ - - priv->mtd.erase = sst25_erase; - priv->mtd.bread = sst25_bread; - priv->mtd.bwrite = sst25_bwrite; - priv->mtd.read = sst25_read; - priv->mtd.ioctl = sst25_ioctl; - priv->dev = dev; - - /* Deselect the FLASH */ - - SPI_SELECT(dev, SPIDEV_FLASH, false); - - /* Identify the FLASH chip and get its capacity */ - - ret = sst25_readid(priv); - if (ret != OK) - { - /* Unrecognized! Discard all of that work we just did and return NULL */ - - fdbg("Unrecognized\n"); - kfree(priv); - priv = NULL; - } - else - { - /* Make sure the the FLASH is unprotected so that we can write into it */ - -#ifndef CONFIG_SST25_READONLY - sst25_unprotect(priv->dev); -#endif - -#ifdef CONFIG_SST25_SECTOR512 /* Simulate a 512 byte sector */ - /* Allocate a buffer for the erase block cache */ - - priv->sector = (FAR uint8_t *)kmalloc(1 << priv->sectorshift); - if (!priv->sector) - { - /* Allocation failed! Discard all of that work we just did and return NULL */ - - fdbg("Allocation failed\n"); - kfree(priv); - priv = NULL; - } -#endif - } - } - - /* Return the implementation-specific state structure as the MTD device */ - - fvdbg("Return %p\n", priv); - return (FAR struct mtd_dev_s *)priv; -} diff --git a/nuttx/drivers/mtd/w25.c b/nuttx/drivers/mtd/w25.c deleted file mode 100644 index bd6680fdf..000000000 --- a/nuttx/drivers/mtd/w25.c +++ /dev/null @@ -1,1179 +0,0 @@ -/************************************************************************************ - * drivers/mtd/w25.c - * Driver for SPI-based W25x16, x32, and x64 and W25q16, q32, q64, and q128 FLASH - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ -/* Configuration ********************************************************************/ -/* Per the data sheet, the W25 parts can be driven with either SPI mode 0 (CPOL=0 - * and CPHA=0) or mode 3 (CPOL=1 and CPHA=1). But I have heard that other devices - * can operate in mode 0 or 1. So you may need to specify CONFIG_W25_SPIMODE to - * select the best mode for your device. If CONFIG_W25_SPIMODE is not defined, - * mode 0 will be used. - */ - -#ifndef CONFIG_W25_SPIMODE -# define CONFIG_W25_SPIMODE SPIDEV_MODE0 -#endif - -/* SPI Frequency. May be up to 25MHz. */ - -#ifndef CONFIG_W25_SPIFREQUENCY -# define CONFIG_W25_SPIFREQUENCY 20000000 -#endif - -/* W25 Instructions *****************************************************************/ -/* Command Value Description */ -/* */ -#define W25_WREN 0x06 /* Write enable */ -#define W25_WRDI 0x04 /* Write Disable */ -#define W25_RDSR 0x05 /* Read status register */ -#define W25_WRSR 0x01 /* Write Status Register */ -#define W25_RDDATA 0x03 /* Read data bytes */ -#define W25_FRD 0x0b /* Higher speed read */ -#define W25_FRDD 0x3b /* Fast read, dual output */ -#define W25_PP 0x02 /* Program page */ -#define W25_BE 0xd8 /* Block Erase (64KB) */ -#define W25_SE 0x20 /* Sector erase (4KB) */ -#define W25_CE 0xc7 /* Chip erase */ -#define W25_PD 0xb9 /* Power down */ -#define W25_PURDID 0xab /* Release PD, Device ID */ -#define W25_RDMFID 0x90 /* Read Manufacturer / Device */ -#define W25_JEDEC_ID 0x9f /* JEDEC ID read */ - -/* W25 Registers ********************************************************************/ -/* Read ID (RDID) register values */ - -#define W25_MANUFACTURER 0xef /* Winbond Serial Flash */ -#define W25X16_DEVID 0x14 /* W25X16 device ID (0xab, 0x90) */ -#define W25X32_DEVID 0x15 /* W25X16 device ID (0xab, 0x90) */ -#define W25X64_DEVID 0x16 /* W25X16 device ID (0xab, 0x90) */ - -/* JEDEC Read ID register values */ - -#define W25_JEDEC_MANUFACTURER 0xef /* SST manufacturer ID */ -#define W25X_JEDEC_MEMORY_TYPE 0x30 /* W25X memory type */ -#define W25Q_JEDEC_MEMORY_TYPE_A 0x40 /* W25Q memory type */ -#define W25Q_JEDEC_MEMORY_TYPE_B 0x60 /* W25Q memory type */ - -#define W25_JEDEC_CAPACITY_16MBIT 0x15 /* 512x4096 = 16Mbit memory capacity */ -#define W25_JEDEC_CAPACITY_32MBIT 0x16 /* 1024x4096 = 32Mbit memory capacity */ -#define W25_JEDEC_CAPACITY_64MBIT 0x17 /* 2048x4096 = 64Mbit memory capacity */ -#define W25_JEDEC_CAPACITY_128MBIT 0x18 /* 4096x4096 = 128Mbit memory capacity */ - -#define NSECTORS_16MBIT 512 /* 512 sectors x 4096 bytes/sector = 2Mb */ -#define NSECTORS_32MBIT 1024 /* 1024 sectors x 4096 bytes/sector = 4Mb */ -#define NSECTORS_64MBIT 2048 /* 2048 sectors x 4096 bytes/sector = 8Mb */ -#define NSECTORS_128MBIT 4096 /* 4096 sectors x 4096 bytes/sector = 16Mb */ - -/* Status register bit definitions */ - -#define W25_SR_BUSY (1 << 0) /* Bit 0: Write in progress */ -#define W25_SR_WEL (1 << 1) /* Bit 1: Write enable latch bit */ -#define W25_SR_BP_SHIFT (2) /* Bits 2-5: Block protect bits */ -#define W25_SR_BP_MASK (15 << W25_SR_BP_SHIFT) -# define W25X16_SR_BP_NONE (0 << W25_SR_BP_SHIFT) /* Unprotected */ -# define W25X16_SR_BP_UPPER32nd (1 << W25_SR_BP_SHIFT) /* Upper 32nd */ -# define W25X16_SR_BP_UPPER16th (2 << W25_SR_BP_SHIFT) /* Upper 16th */ -# define W25X16_SR_BP_UPPER8th (3 << W25_SR_BP_SHIFT) /* Upper 8th */ -# define W25X16_SR_BP_UPPERQTR (4 << W25_SR_BP_SHIFT) /* Upper quarter */ -# define W25X16_SR_BP_UPPERHALF (5 << W25_SR_BP_SHIFT) /* Upper half */ -# define W25X16_SR_BP_ALL (6 << W25_SR_BP_SHIFT) /* All sectors */ -# define W25X16_SR_BP_LOWER32nd (9 << W25_SR_BP_SHIFT) /* Lower 32nd */ -# define W25X16_SR_BP_LOWER16th (10 << W25_SR_BP_SHIFT) /* Lower 16th */ -# define W25X16_SR_BP_LOWER8th (11 << W25_SR_BP_SHIFT) /* Lower 8th */ -# define W25X16_SR_BP_LOWERQTR (12 << W25_SR_BP_SHIFT) /* Lower quarter */ -# define W25X16_SR_BP_LOWERHALF (13 << W25_SR_BP_SHIFT) /* Lower half */ - -# define W25X32_SR_BP_NONE (0 << W25_SR_BP_SHIFT) /* Unprotected */ -# define W25X32_SR_BP_UPPER64th (1 << W25_SR_BP_SHIFT) /* Upper 64th */ -# define W25X32_SR_BP_UPPER32nd (2 << W25_SR_BP_SHIFT) /* Upper 32nd */ -# define W25X32_SR_BP_UPPER16th (3 << W25_SR_BP_SHIFT) /* Upper 16th */ -# define W25X32_SR_BP_UPPER8th (4 << W25_SR_BP_SHIFT) /* Upper 8th */ -# define W25X32_SR_BP_UPPERQTR (5 << W25_SR_BP_SHIFT) /* Upper quarter */ -# define W25X32_SR_BP_UPPERHALF (6 << W25_SR_BP_SHIFT) /* Upper half */ -# define W25X32_SR_BP_ALL (7 << W25_SR_BP_SHIFT) /* All sectors */ -# define W25X32_SR_BP_LOWER64th (9 << W25_SR_BP_SHIFT) /* Lower 64th */ -# define W25X32_SR_BP_LOWER32nd (10 << W25_SR_BP_SHIFT) /* Lower 32nd */ -# define W25X32_SR_BP_LOWER16th (11 << W25_SR_BP_SHIFT) /* Lower 16th */ -# define W25X32_SR_BP_LOWER8th (12 << W25_SR_BP_SHIFT) /* Lower 8th */ -# define W25X32_SR_BP_LOWERQTR (13 << W25_SR_BP_SHIFT) /* Lower quarter */ -# define W25X32_SR_BP_LOWERHALF (14 << W25_SR_BP_SHIFT) /* Lower half */ - -# define W25X64_SR_BP_NONE (0 << W25_SR_BP_SHIFT) /* Unprotected */ -# define W25X64_SR_BP_UPPER64th (1 << W25_SR_BP_SHIFT) /* Upper 64th */ -# define W25X64_SR_BP_UPPER32nd (2 << W25_SR_BP_SHIFT) /* Upper 32nd */ -# define W25X64_SR_BP_UPPER16th (3 << W25_SR_BP_SHIFT) /* Upper 16th */ -# define W25X64_SR_BP_UPPER8th (4 << W25_SR_BP_SHIFT) /* Upper 8th */ -# define W25X64_SR_BP_UPPERQTR (5 << W25_SR_BP_SHIFT) /* Upper quarter */ -# define W25X64_SR_BP_UPPERHALF (6 << W25_SR_BP_SHIFT) /* Upper half */ -# define W25X46_SR_BP_ALL (7 << W25_SR_BP_SHIFT) /* All sectors */ -# define W25X64_SR_BP_LOWER64th (9 << W25_SR_BP_SHIFT) /* Lower 64th */ -# define W25X64_SR_BP_LOWER32nd (10 << W25_SR_BP_SHIFT) /* Lower 32nd */ -# define W25X64_SR_BP_LOWER16th (11 << W25_SR_BP_SHIFT) /* Lower 16th */ -# define W25X64_SR_BP_LOWER8th (12 << W25_SR_BP_SHIFT) /* Lower 8th */ -# define W25X64_SR_BP_LOWERQTR (13 << W25_SR_BP_SHIFT) /* Lower quarter */ -# define W25X64_SR_BP_LOWERHALF (14 << W25_SR_BP_SHIFT) /* Lower half */ - /* Bit 6: Reserved */ -#define W25_SR_SRP (1 << 7) /* Bit 7: Status register write protect */ - -#define W25_DUMMY 0xa5 - -/* Chip Geometries ******************************************************************/ -/* All members of the family support uniform 4K-byte sectors and 256 byte pages */ - -#define W25_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4Kb */ -#define W25_SECTOR_SIZE (1 << 12) /* Sector size 1 << 12 = 4Kb */ -#define W25_PAGE_SHIFT 8 /* Sector size 1 << 8 = 256b */ -#define W25_PAGE_SIZE (1 << 8) /* Sector size 1 << 8 = 256b */ - -#ifdef CONFIG_W25_SECTOR512 /* Simulate a 512 byte sector */ -# define W25_SECTOR512_SHIFT 9 /* Sector size 1 << 9 = 512 bytes */ -# define W25_SECTOR512_SIZE (1 << 9) /* Sector size 1 << 9 = 512 bytes */ -#endif - -#define W25_ERASED_STATE 0xff /* State of FLASH when erased */ - -/* Cache flags */ - -#define W25_CACHE_VALID (1 << 0) /* 1=Cache has valid data */ -#define W25_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */ -#define W25_CACHE_ERASED (1 << 2) /* 1=Backing FLASH is erased */ - -#define IS_VALID(p) ((((p)->flags) & W25_CACHE_VALID) != 0) -#define IS_DIRTY(p) ((((p)->flags) & W25_CACHE_DIRTY) != 0) -#define IS_ERASED(p) ((((p)->flags) & W25_CACHE_DIRTY) != 0) - -#define SET_VALID(p) do { (p)->flags |= W25_CACHE_VALID; } while (0) -#define SET_DIRTY(p) do { (p)->flags |= W25_CACHE_DIRTY; } while (0) -#define SET_ERASED(p) do { (p)->flags |= W25_CACHE_DIRTY; } while (0) - -#define CLR_VALID(p) do { (p)->flags &= ~W25_CACHE_VALID; } while (0) -#define CLR_DIRTY(p) do { (p)->flags &= ~W25_CACHE_DIRTY; } while (0) -#define CLR_ERASED(p) do { (p)->flags &= ~W25_CACHE_DIRTY; } while (0) - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/* This type represents the state of the MTD device. The struct mtd_dev_s must - * appear at the beginning of the definition so that you can freely cast between - * pointers to struct mtd_dev_s and struct w25_dev_s. - */ - -struct w25_dev_s -{ - struct mtd_dev_s mtd; /* MTD interface */ - FAR struct spi_dev_s *spi; /* Saved SPI interface instance */ - uint16_t nsectors; /* Number of erase sectors */ - -#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY) - uint8_t flags; /* Buffered sector flags */ - uint16_t esectno; /* Erase sector number in the cache*/ - FAR uint8_t *sector; /* Allocated sector data */ -#endif -}; - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/* Helpers */ - -static void w25_lock(FAR struct spi_dev_s *spi); -static inline void w25_unlock(FAR struct spi_dev_s *spi); -static inline int w25_readid(FAR struct w25_dev_s *priv); -#ifndef CONFIG_W25_READONLY -static void w25_unprotect(FAR struct w25_dev_s *priv); -#endif -static uint8_t w25_waitwritecomplete(FAR struct w25_dev_s *priv); -static inline void w25_wren(FAR struct w25_dev_s *priv); -static inline void w25_wrdi(FAR struct w25_dev_s *priv); -static void w25_sectorerase(FAR struct w25_dev_s *priv, off_t offset); -static inline int w25_chiperase(FAR struct w25_dev_s *priv); -static void w25_byteread(FAR struct w25_dev_s *priv, FAR uint8_t *buffer, - off_t address, size_t nbytes); -#ifndef CONFIG_W25_READONLY -static void w25_pagewrite(FAR struct w25_dev_s *priv, FAR const uint8_t *buffer, - off_t address, size_t nbytes); -#endif -#ifdef CONFIG_W25_SECTOR512 -static void w25_cacheflush(struct w25_dev_s *priv); -static FAR uint8_t *w25_cacheread(struct w25_dev_s *priv, off_t sector); -static void w25_cacheerase(struct w25_dev_s *priv, off_t sector); -static void w25_cachewrite(FAR struct w25_dev_s *priv, FAR const uint8_t *buffer, - off_t sector, size_t nsectors); -#endif - -/* MTD driver methods */ - -static int w25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static ssize_t w25_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buf); -static ssize_t w25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); -static ssize_t w25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int w25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: w25_lock - ************************************************************************************/ - -static void w25_lock(FAR struct spi_dev_s *spi) -{ - /* On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of - * transfers. The bus should be locked before the chip is selected. - * - * This is a blocking call and will not return until we have exclusiv access to - * the SPI buss. We will retain that exclusive access until the bus is unlocked. - */ - - (void)SPI_LOCK(spi, true); - - /* After locking the SPI bus, the we also need call the setfrequency, setbits, and - * setmode methods to make sure that the SPI is properly configured for the device. - * If the SPI buss is being shared, then it may have been left in an incompatible - * state. - */ - - SPI_SETMODE(spi, CONFIG_W25_SPIMODE); - SPI_SETBITS(spi, 8); - (void)SPI_SETFREQUENCY(spi, CONFIG_W25_SPIFREQUENCY); -} - -/************************************************************************************ - * Name: w25_unlock - ************************************************************************************/ - -static inline void w25_unlock(FAR struct spi_dev_s *spi) -{ - (void)SPI_LOCK(spi, false); -} - -/************************************************************************************ - * Name: w25_readid - ************************************************************************************/ - -static inline int w25_readid(struct w25_dev_s *priv) -{ - uint16_t manufacturer; - uint16_t memory; - uint16_t capacity; - - fvdbg("priv: %p\n", priv); - - /* Lock the SPI bus, configure the bus, and select this FLASH part. */ - - w25_lock(priv->spi); - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send the "Read ID (RDID)" command and read the first three ID bytes */ - - (void)SPI_SEND(priv->spi, W25_JEDEC_ID); - manufacturer = SPI_SEND(priv->spi, W25_DUMMY); - memory = SPI_SEND(priv->spi, W25_DUMMY); - capacity = SPI_SEND(priv->spi, W25_DUMMY); - - /* Deselect the FLASH and unlock the bus */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - w25_unlock(priv->spi); - - fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n", - manufacturer, memory, capacity); - - /* Check for a valid manufacturer and memory type */ - - if (manufacturer == W25_JEDEC_MANUFACTURER && - (memory == W25X_JEDEC_MEMORY_TYPE || - memory == W25Q_JEDEC_MEMORY_TYPE_A || - memory == W25Q_JEDEC_MEMORY_TYPE_B)) - { - /* Okay.. is it a FLASH capacity that we understand? If so, save - * the FLASH capacity. - */ - - /* 16M-bit / 2M-byte (2,097,152) - * - * W24X16, W25Q16BV, W25Q16CL, W25Q16CV, W25Q16DW - */ - - if (capacity == W25_JEDEC_CAPACITY_16MBIT) - { - priv->nsectors = NSECTORS_16MBIT; - } - - /* 32M-bit / M-byte (4,194,304) - * - * W25X32, W25Q32BV, W25Q32DW - */ - - else if (capacity == W25_JEDEC_CAPACITY_32MBIT) - { - priv->nsectors = NSECTORS_32MBIT; - } - - /* 64M-bit / 8M-byte (8,388,608) - * - * W25X64, W25Q64BV, W25Q64CV, W25Q64DW - */ - - else if (capacity == W25_JEDEC_CAPACITY_64MBIT) - { - priv->nsectors = NSECTORS_64MBIT; - } - - /* 128M-bit / 16M-byte (16,777,216) - * - * W25Q128BV - */ - - else if (capacity == W25_JEDEC_CAPACITY_128MBIT) - { - priv->nsectors = NSECTORS_128MBIT; - } - else - { - /* Nope.. we don't understand this capacity. */ - - return -ENODEV; - } - - return OK; - } - - /* We don't understand the manufacturer or the memory type */ - - return -ENODEV; -} - -/************************************************************************************ - * Name: w25_unprotect - ************************************************************************************/ - -#ifndef CONFIG_W25_READONLY -static void w25_unprotect(FAR struct w25_dev_s *priv) -{ - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send "Write enable (WREN)" */ - - w25_wren(priv); - - /* Re-select this FLASH part (This might not be necessary... but is it shown in - * the SST25 timing diagrams from which this code was leveraged.) - */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send "Write enable status (EWSR)" */ - - SPI_SEND(priv->spi, W25_WRSR); - - /* Following by the new status value */ - - SPI_SEND(priv->spi, 0); - SPI_SEND(priv->spi, 0); -} -#endif - -/************************************************************************************ - * Name: w25_waitwritecomplete - ************************************************************************************/ - -static uint8_t w25_waitwritecomplete(struct w25_dev_s *priv) -{ - uint8_t status; - - /* Are we the only device on the bus? */ - -#ifdef CONFIG_SPI_OWNBUS - - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->spi, W25_RDSR); - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->spi, W25_DUMMY); - } - while ((status & W25_SR_BUSY) != 0); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - -#else - - /* Loop as long as the memory is busy with a write cycle */ - - do - { - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send "Read Status Register (RDSR)" command */ - - (void)SPI_SEND(priv->spi, W25_RDSR); - - /* Send a dummy byte to generate the clock needed to shift out the status */ - - status = SPI_SEND(priv->spi, W25_DUMMY); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - - /* Given that writing could take up to few tens of milliseconds, and erasing - * could take more. The following short delay in the "busy" case will allow - * other peripherals to access the SPI bus. - */ - -#if 0 /* Makes writes too slow */ - if ((status & W25_SR_BUSY) != 0) - { - w25_unlock(priv->spi); - usleep(1000); - w25_lock(priv->spi); - } -#endif - } - while ((status & W25_SR_BUSY) != 0); -#endif - - return status; -} - -/************************************************************************************ - * Name: w25_wren - ************************************************************************************/ - -static inline void w25_wren(struct w25_dev_s *priv) -{ - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send "Write Enable (WREN)" command */ - - (void)SPI_SEND(priv->spi, W25_WREN); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: w25_wrdi - ************************************************************************************/ - -static inline void w25_wrdi(struct w25_dev_s *priv) -{ - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send "Write Disable (WRDI)" command */ - - (void)SPI_SEND(priv->spi, W25_WRDI); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: w25_sectorerase - ************************************************************************************/ - -static void w25_sectorerase(struct w25_dev_s *priv, off_t sector) -{ - off_t address = sector << W25_SECTOR_SHIFT; - - fvdbg("sector: %08lx\n", (long)sector); - - /* Wait for any preceding write or erase operation to complete. */ - - (void)w25_waitwritecomplete(priv); - - /* Send write enable instruction */ - - w25_wren(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send the "Sector Erase (SE)" instruction */ - - (void)SPI_SEND(priv->spi, W25_SE); - - /* Send the sector address high byte first. Only the most significant bits (those - * corresponding to the sector) have any meaning. - */ - - (void)SPI_SEND(priv->spi, (address >> 16) & 0xff); - (void)SPI_SEND(priv->spi, (address >> 8) & 0xff); - (void)SPI_SEND(priv->spi, address & 0xff); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: w25_chiperase - ************************************************************************************/ - -static inline int w25_chiperase(struct w25_dev_s *priv) -{ - fvdbg("priv: %p\n", priv); - - /* Wait for any preceding write or erase operation to complete. */ - - (void)w25_waitwritecomplete(priv); - - /* Send write enable instruction */ - - w25_wren(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send the "Chip Erase (CE)" instruction */ - - (void)SPI_SEND(priv->spi, W25_CE); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - fvdbg("Return: OK\n"); - return OK; -} - -/************************************************************************************ - * Name: w25_byteread - ************************************************************************************/ - -static void w25_byteread(FAR struct w25_dev_s *priv, FAR uint8_t *buffer, - off_t address, size_t nbytes) -{ - uint8_t status; - - fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes); - - /* Wait for any preceding write or erase operation to complete. */ - - status = w25_waitwritecomplete(priv); - DEBUGASSERT((status & (W25_SR_WEL|W25_SR_BP_MASK)) == 0); - - /* Make sure that writing is disabled */ - - w25_wrdi(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send "Read from Memory " instruction */ - -#ifdef CONFIG_W25_SLOWREAD - (void)SPI_SEND(priv->spi, W25_RDDATA); -#else - (void)SPI_SEND(priv->spi, W25_FRD); -#endif - - /* Send the address high byte first. */ - - (void)SPI_SEND(priv->spi, (address >> 16) & 0xff); - (void)SPI_SEND(priv->spi, (address >> 8) & 0xff); - (void)SPI_SEND(priv->spi, address & 0xff); - - /* Send a dummy byte */ - -#ifndef CONFIG_W25_SLOWREAD - (void)SPI_SEND(priv->spi, W25_DUMMY); -#endif - - /* Then read all of the requested bytes */ - - SPI_RECVBLOCK(priv->spi, buffer, nbytes); - - /* Deselect the FLASH */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); -} - -/************************************************************************************ - * Name: w25_pagewrite - ************************************************************************************/ - -#ifndef CONFIG_W25_READONLY -static void w25_pagewrite(struct w25_dev_s *priv, FAR const uint8_t *buffer, - off_t address, size_t nbytes) -{ - uint8_t status; - - fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nbytes); - DEBUGASSERT(priv && buffer && (address & 0xff) == 0 && - (nbytes & 0xff) == 0); - - for (; nbytes > 0; nbytes -= W25_PAGE_SIZE) - { - /* Wait for any preceding write or erase operation to complete. */ - - status = w25_waitwritecomplete(priv); - DEBUGASSERT((status & (W25_SR_WEL|W25_SR_BP_MASK)) == 0); - - /* Enable write access to the FLASH */ - - w25_wren(priv); - - /* Select this FLASH part */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, true); - - /* Send the "Page Program (W25_PP)" Command */ - - SPI_SEND(priv->spi, W25_PP); - - /* Send the address high byte first. */ - - (void)SPI_SEND(priv->spi, (address >> 16) & 0xff); - (void)SPI_SEND(priv->spi, (address >> 8) & 0xff); - (void)SPI_SEND(priv->spi, address & 0xff); - - /* Then send the page of data */ - - SPI_SNDBLOCK(priv->spi, buffer, W25_PAGE_SIZE); - - /* Deselect the FLASH and setup for the next pass through the loop */ - - SPI_SELECT(priv->spi, SPIDEV_FLASH, false); - - /* Update addresses */ - - address += W25_PAGE_SIZE; - buffer += W25_PAGE_SIZE; - } - - /* Disable writing */ - - w25_wrdi(priv); -} -#endif - -/************************************************************************************ - * Name: w25_cacheflush - ************************************************************************************/ - -#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY) -static void w25_cacheflush(struct w25_dev_s *priv) -{ - /* If the cached is dirty (meaning that it no longer matches the old FLASH contents) - * or was erased (with the cache containing the correct FLASH contents), then write - * the cached erase block to FLASH. - */ - - if (IS_DIRTY(priv) || IS_ERASED(priv)) - { - /* Write entire erase block to FLASH */ - - w25_pagewrite(priv, priv->sector, (off_t)priv->esectno << W25_SECTOR_SHIFT, - W25_SECTOR_SIZE); - - /* The case is no long dirty and the FLASH is no longer erased */ - - CLR_DIRTY(priv); - CLR_ERASED(priv); - } -} -#endif - -/************************************************************************************ - * Name: w25_cacheread - ************************************************************************************/ - -#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY) -static FAR uint8_t *w25_cacheread(struct w25_dev_s *priv, off_t sector) -{ - off_t esectno; - int shift; - int index; - - /* Convert from the 512 byte sector to the erase sector size of the device. For - * exmample, if the actual erase sector size if 4Kb (1 << 12), then we first - * shift to the right by 3 to get the sector number in 4096 increments. - */ - - shift = W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT; - esectno = sector >> shift; - fvdbg("sector: %ld esectno: %d shift=%d\n", sector, esectno, shift); - - /* Check if the requested erase block is already in the cache */ - - if (!IS_VALID(priv) || esectno != priv->esectno) - { - /* No.. Flush any dirty erase block currently in the cache */ - - w25_cacheflush(priv); - - /* Read the erase block into the cache */ - - w25_byteread(priv, priv->sector, (esectno << W25_SECTOR_SHIFT), W25_SECTOR_SIZE); - - /* Mark the sector as cached */ - - priv->esectno = esectno; - - SET_VALID(priv); /* The data in the cache is valid */ - CLR_DIRTY(priv); /* It should match the FLASH contents */ - CLR_ERASED(priv); /* The underlying FLASH has not been erased */ - } - - /* Get the index to the 512 sector in the erase block that holds the argument */ - - index = sector & ((1 << shift) - 1); - - /* Return the address in the cache that holds this sector */ - - return &priv->sector[index << W25_SECTOR512_SHIFT]; -} -#endif - -/************************************************************************************ - * Name: w25_cacheerase - ************************************************************************************/ - -#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY) -static void w25_cacheerase(struct w25_dev_s *priv, off_t sector) -{ - FAR uint8_t *dest; - - /* First, make sure that the erase block containing the 512 byte sector is in - * the cache. - */ - - dest = w25_cacheread(priv, sector); - - /* Erase the block containing this sector if it is not already erased. - * The erased indicated will be cleared when the data from the erase sector - * is read into the cache and set here when we erase the block. - */ - - if (!IS_ERASED(priv)) - { - off_t esectno = sector >> (W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT); - fvdbg("sector: %ld esectno: %d\n", sector, esectno); - - w25_sectorerase(priv, esectno); - SET_ERASED(priv); - } - - /* Put the cached sector data into the erase state and mart the cache as dirty - * (but don't update the FLASH yet. The caller will do that at a more optimal - * time). - */ - - memset(dest, W25_ERASED_STATE, W25_SECTOR512_SIZE); - SET_DIRTY(priv); -} -#endif - -/************************************************************************************ - * Name: w25_cachewrite - ************************************************************************************/ - -#if defined(CONFIG_W25_SECTOR512) && !defined(CONFIG_W25_READONLY) -static void w25_cachewrite(FAR struct w25_dev_s *priv, FAR const uint8_t *buffer, - off_t sector, size_t nsectors) -{ - FAR uint8_t *dest; - - for (; nsectors > 0; nsectors--) - { - /* First, make sure that the erase block containing 512 byte sector is in - * memory. - */ - - dest = w25_cacheread(priv, sector); - - /* Erase the block containing this sector if it is not already erased. - * The erased indicated will be cleared when the data from the erase sector - * is read into the cache and set here when we erase the sector. - */ - - if (!IS_ERASED(priv)) - { - off_t esectno = sector >> (W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT); - fvdbg("sector: %ld esectno: %d\n", sector, esectno); - - w25_sectorerase(priv, esectno); - SET_ERASED(priv); - } - - /* Copy the new sector data into cached erase block */ - - memcpy(dest, buffer, W25_SECTOR512_SIZE); - SET_DIRTY(priv); - - /* Set up for the next 512 byte sector */ - - buffer += W25_SECTOR512_SIZE; - sector++; - } - - /* Flush the last erase block left in the cache */ - - w25_cacheflush(priv); -} -#endif - -/************************************************************************************ - * Name: w25_erase - ************************************************************************************/ - -static int w25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) -{ -#ifdef CONFIG_W25_READONLY - return -EACESS -#else - FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev; - size_t blocksleft = nblocks; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock access to the SPI bus until we complete the erase */ - - w25_lock(priv->spi); - - while (blocksleft-- > 0) - { - /* Erase each sector */ - -#ifdef CONFIG_W25_SECTOR512 - w25_cacheerase(priv, startblock); -#else - w25_sectorerase(priv, startblock); -#endif - startblock++; - } - -#ifdef CONFIG_W25_SECTOR512 - /* Flush the last erase block left in the cache */ - - w25_cacheflush(priv); -#endif - - w25_unlock(priv->spi); - return (int)nblocks; -#endif -} - -/************************************************************************************ - * Name: w25_bread - ************************************************************************************/ - -static ssize_t w25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buffer) -{ - ssize_t nbytes; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* On this device, we can handle the block read just like the byte-oriented read */ - -#ifdef CONFIG_W25_SECTOR512 - nbytes = w25_read(dev, startblock << W25_SECTOR512_SHIFT, nblocks << W25_SECTOR512_SHIFT, buffer); - if (nbytes > 0) - { - nbytes >>= W25_SECTOR512_SHIFT; - } -#else - nbytes = w25_read(dev, startblock << W25_SECTOR_SHIFT, nblocks << W25_SECTOR_SHIFT, buffer); - if (nbytes > 0) - { - nbytes >>= W25_SECTOR_SHIFT; - } -#endif - - return nbytes; -} - -/************************************************************************************ - * Name: w25_bwrite - ************************************************************************************/ - -static ssize_t w25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) -{ -#ifdef CONFIG_W25_READONLY - return -EACCESS; -#else - FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev; - - fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); - - /* Lock the SPI bus and write all of the pages to FLASH */ - - w25_lock(priv->spi); - -#if defined(CONFIG_W25_SECTOR512) - w25_cachewrite(priv, buffer, startblock, nblocks); -#else - w25_pagewrite(priv, buffer, startblock << W25_SECTOR_SHIFT, - nblocks << W25_SECTOR_SHIFT); -#endif - w25_unlock(priv->spi); - - return nblocks; -#endif -} - -/************************************************************************************ - * Name: w25_read - ************************************************************************************/ - -static ssize_t w25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer) -{ - FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev; - - fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); - - /* Lock the SPI bus and select this FLASH part */ - - w25_lock(priv->spi); - w25_byteread(priv, buffer, offset, nbytes); - w25_unlock(priv->spi); - - fvdbg("return nbytes: %d\n", (int)nbytes); - return nbytes; -} - -/************************************************************************************ - * Name: w25_ioctl - ************************************************************************************/ - -static int w25_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct w25_dev_s *priv = (FAR struct w25_dev_s *)dev; - int ret = -EINVAL; /* Assume good command with bad parameters */ - - fvdbg("cmd: %d \n", cmd); - - switch (cmd) - { - case MTDIOC_GEOMETRY: - { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); - if (geo) - { - /* Populate the geometry structure with information need to know - * the capacity and how to access the device. - * - * NOTE: that the device is treated as though it where just an array - * of fixed size blocks. That is most likely not true, but the client - * will expect the device logic to do whatever is necessary to make it - * appear so. - */ - -#ifdef CONFIG_W25_SECTOR512 - geo->blocksize = (1 << W25_SECTOR512_SHIFT); - geo->erasesize = (1 << W25_SECTOR512_SHIFT); - geo->neraseblocks = priv->nsectors << (W25_SECTOR_SHIFT - W25_SECTOR512_SHIFT); -#else - geo->blocksize = W25_SECTOR_SIZE; - geo->erasesize = W25_SECTOR_SIZE; - geo->neraseblocks = priv->nsectors; -#endif - ret = OK; - - fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); - } - } - break; - - case MTDIOC_BULKERASE: - { - /* Erase the entire device */ - - w25_lock(priv->spi); - ret = w25_chiperase(priv); - w25_unlock(priv->spi); - } - break; - - case MTDIOC_XIPBASE: - default: - ret = -ENOTTY; /* Bad command */ - break; - } - - fvdbg("return %d\n", ret); - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: w25_initialize - * - * Description: - * Create an initialize MTD device instance. MTD devices are not registered - * in the file system, but are created as instances that can be bound to - * other functions (such as a block or character driver front end). - * - ************************************************************************************/ - -FAR struct mtd_dev_s *w25_initialize(FAR struct spi_dev_s *spi) -{ - FAR struct w25_dev_s *priv; - int ret; - - fvdbg("spi: %p\n", spi); - - /* Allocate a state structure (we allocate the structure instead of using - * a fixed, static allocation so that we can handle multiple FLASH devices. - * The current implementation would handle only one FLASH part per SPI - * device (only because of the SPIDEV_FLASH definition) and so would have - * to be extended to handle multiple FLASH parts on the same SPI bus. - */ - - priv = (FAR struct w25_dev_s *)kzalloc(sizeof(struct w25_dev_s)); - if (priv) - { - /* Initialize the allocated structure */ - - priv->mtd.erase = w25_erase; - priv->mtd.bread = w25_bread; - priv->mtd.bwrite = w25_bwrite; - priv->mtd.read = w25_read; - priv->mtd.ioctl = w25_ioctl; - priv->spi = spi; - - /* Deselect the FLASH */ - - SPI_SELECT(spi, SPIDEV_FLASH, false); - - /* Identify the FLASH chip and get its capacity */ - - ret = w25_readid(priv); - if (ret != OK) - { - /* Unrecognized! Discard all of that work we just did and return NULL */ - - fdbg("Unrecognized\n"); - kfree(priv); - priv = NULL; - } - else - { - /* Make sure the the FLASH is unprotected so that we can write into it */ - -#ifndef CONFIG_W25_READONLY - w25_unprotect(priv); -#endif - -#ifdef CONFIG_W25_SECTOR512 /* Simulate a 512 byte sector */ - /* Allocate a buffer for the erase block cache */ - - priv->sector = (FAR uint8_t *)kmalloc(W25_SECTOR_SIZE); - if (!priv->sector) - { - /* Allocation failed! Discard all of that work we just did and return NULL */ - - fdbg("Allocation failed\n"); - kfree(priv); - priv = NULL; - } -#endif - } - } - - /* Return the implementation-specific state structure as the MTD device */ - - fvdbg("Return %p\n", priv); - return (FAR struct mtd_dev_s *)priv; -} diff --git a/nuttx/drivers/net/Kconfig b/nuttx/drivers/net/Kconfig deleted file mode 100644 index d8878ecaf..000000000 --- a/nuttx/drivers/net/Kconfig +++ /dev/null @@ -1,95 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# -config NET_DM90x0 - bool "Davicom dm9000/dm9010 support" - default n - ---help--- - References: Davicom data sheets (DM9000-DS-F03-041906.pdf, - DM9010-DS-F01-103006.pdf) and looking at lots of other DM90x0 - drivers. - -config NET_CS89x0 - bool "CS89x0 support" - default n - depends on EXPERIMENTAL - ---help--- - Under construction -- do not use - -config ENC28J60 - bool "Microchip ENC28J60 support" - default n - select SPI - ---help--- - References: - ENC28J60 Data Sheet, Stand-Alone Ethernet Controller with SPI Interface, - DS39662C, 2008 Microchip Technology Inc. - -if ENC28J60 -config ENC28J60_NINTERFACES - int "Number of physical ENC28J60" - default 1 - range 1,1 - ---help--- - Specifies the number of physical ENC28J60 - devices that will be supported. - -config ENC28J60_SPIMODE - int "SPI mode" - default 0 - ---help--- - Controls the SPI mode. The ENC28J60 spec says that it supports SPI - mode 0,0 only: "The implementation used on this device supports SPI - mode 0,0 only. In addition, the SPI port requires that SCK be at Idle - in a low state; selectable clock polarity is not supported." - However, sometimes you need to tinker with these things. - -config ENC28J60_FREQUENCY - int "SPI frequency" - default 20000000 - ---help--- - Define to use a different bus frequency - -config ENC28J60_STATS - bool "Network statistics support" - default n - ---help--- - Collect network statistics - -config ENC28J60_HALFDUPPLEX - bool "Enable half dupplex" - default n - ---help--- - Default is full duplex - -config ENC28J60_DUMPPACKET - bool "Dump Packets" - default n - ---help--- - If selected, the ENC28J60 driver will dump the contents of each - packet to the console. - -config ENC28J60_REGDEBUG - bool "Register-Level Debug" - default n - depends on DEBUG && DEBUG_NET - ---help--- - Enable very low-level register access debug. Depends on DEBUG and DEBUG_NET. - -endif - -config NET_E1000 - bool "E1000 support" - default n - -config NET_SLIP - bool "SLIP (serial line) support" - default n - ---help--- - Reference: RFC 1055 - -config NET_VNET - bool "VNET support" - default n - diff --git a/nuttx/drivers/net/Make.defs b/nuttx/drivers/net/Make.defs deleted file mode 100644 index bb0d6a718..000000000 --- a/nuttx/drivers/net/Make.defs +++ /dev/null @@ -1,71 +0,0 @@ -############################################################################ -# drivers/net/Make.defs -# -# Copyright (C) 2007, 2010-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Include nothing if networking is disabled - -ifeq ($(CONFIG_NET),y) - -# Include network interface drivers - -ifeq ($(CONFIG_NET_DM90x0),y) - CSRCS += dm90x0.c -endif - -ifeq ($(CONFIG_NET_CS89x0),y) - CSRCS += cs89x0.c -endif - -ifeq ($(CONFIG_ENC28J60),y) - CSRCS += enc28j60.c -endif - -ifeq ($(CONFIG_NET_VNET),y) - CSRCS += vnet.c -endif - -ifeq ($(CONFIG_NET_E1000),y) - CSRCS += e1000.c -endif - -ifeq ($(CONFIG_NET_SLIP),y) - CSRCS += slip.c -endif - -# Include network build support - -DEPPATH += --dep-path net -VPATH += :net -endif - diff --git a/nuttx/drivers/net/cs89x0.c b/nuttx/drivers/net/cs89x0.c deleted file mode 100644 index 22b9b87a5..000000000 --- a/nuttx/drivers/net/cs89x0.c +++ /dev/null @@ -1,959 +0,0 @@ -/**************************************************************************** - * drivers/net/cs89x0.c - * - * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#if defined(CONFIG_NET) && defined(CONFIG_NET_CS89x0) - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -#error "Under construction -- do not use" - -/* CONFIG_CS89x0_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_CS89x0_NINTERFACES -# define CONFIG_CS89x0_NINTERFACES 1 -#endif - -/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define CS89x0_WDDELAY (1*CLK_TCK) -#define CS89x0_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define CS89x0_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct uip_eth_hdr *)cs89x0->cs_dev.d_buf) - -/* If there is only one CS89x0 instance, then mapping the CS89x0 IRQ to - * a driver state instance is trivial. - */ - -#if CONFIG_CS89x0_NINTERFACES == 1 -# define cs89x0_mapirq(irq) g_cs89x0[0] -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static FAR struct cs89x0_driver_s *g_cs89x0[CONFIG_CS89x0_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* CS89x0 register access */ - -static uint16_t cs89x0_getreg(struct cs89x0_driver_s *cs89x0, int offset); -static void cs89x0_putreg(struct cs89x0_driver_s *cs89x0, int offset, - uint16_t value); -static uint16_t cs89x0_getppreg(struct cs89x0_driver_s *cs89x0, int addr); -static void cs89x0_putppreg(struct cs89x0_driver_s *cs89x0, int addr, - uint16_t value); - -/* Common TX logic */ - -static int cs89x0_transmit(struct cs89x0_driver_s *cs89x0); -static int cs89x0_uiptxpoll(struct uip_driver_s *dev); - -/* Interrupt handling */ - -static void cs89x0_receive(struct cs89x0_driver_s *cs89x0); -static void cs89x0_txdone(struct cs89x0_driver_s *cs89x0, uint16_t isq); -#if CONFIG_CS89x0_NINTERFACES > 1 -static inline FAR struct cs89x0_driver_s *cs89x0_mapirq(int irq); -#endif -static int cs89x0_interrupt(int irq, FAR void *context); - -/* Watchdog timer expirations */ - -static void cs89x0_polltimer(int argc, uint32_t arg, ...); -static void cs89x0_txtimeout(int argc, uint32_t arg, ...); - -/* NuttX callback functions */ - -static int cs89x0_ifup(struct uip_driver_s *dev); -static int cs89x0_ifdown(struct uip_driver_s *dev); -static int cs89x0_txavail(struct uip_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int cs89x0_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -static int cs89x0_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: cs89x0_getreg and cs89x0_putreg - * - * Description: - * Read from and write to a CS89x0 register - * - * Parameters: - * cs89x0 - Reference to the driver state structure - * offset - Offset to the CS89x0 register - * value - Value to be written (cs89x0_putreg only) - * - * Returned Value: - * cs89x0_getreg: The 16-bit value of the register - * cs89x0_putreg: None - * - ****************************************************************************/ - -static uint16_t cs89x0_getreg(struct cs89x0_driver_s *cs89x0, int offset) -{ -#ifdef CONFIG_CS89x0_ALIGN16 - return getreg16(s89x0->cs_base + offset); -#else - return (uint16_t)getreg32(s89x0->cs_base + offset); -#endif -} - -static void cs89x0_putreg(struct cs89x0_driver_s *cs89x0, int offset, uint16_t value) -{ -#ifdef CONFIG_CS89x0_ALIGN16 - return putreg16(value, s89x0->cs_base + offset); -#else - return (uint16_t)putreg32((uint32_t)value, s89x0->cs_base + offset); -#endif -} - -/**************************************************************************** - * Function: cs89x0_getppreg and cs89x0_putppreg - * - * Description: - * Read from and write to a CS89x0 page packet register - * - * Parameters: - * cs89x0 - Reference to the driver state structure - * addr - Address of the CS89x0 page packet register - * value - Value to be written (cs89x0_putppreg only) - * - * Returned Value: - * cs89x0_getppreg: The 16-bit value of the page packet register - * cs89x0_putppreg: None - * - ****************************************************************************/ - -static uint16_t cs89x0_getppreg(struct cs89x0_driver_s *cs89x0, int addr) -{ - /* In memory mode, the CS89x0's internal registers and frame buffers are mapped - * into a contiguous 4kb block providing direct access to the internal registers - * and frame buffers. - */ - -#ifdef CONFIG_CS89x0_MEMMODE - if (cs89x0->cs_memmode) - { -#ifdef CONFIG_CS89x0_ALIGN16 - return getreg16(s89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??)); -#else - return (uint16_t)getreg32(s89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??)); -#endif - } - - /* When configured in I/O mode, the CS89x0 is accessed through eight, 16-bit - * I/O ports that in the host system's I/O space. - */ - - else -#endif - { -#ifdef CONFIG_CS89x0_ALIGN16 - putreg16((uint16_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET); - return getreg16(s89x0->cs_base + CS89x0_PDATA_OFFSET); -#else - putreg32((uint32_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET); - return (uint16_t)getreg32(s89x0->cs_base + CS89x0_PDATA_OFFSET); -#endif - } -} - -static void cs89x0_putppreg(struct cs89x0_driver_s *cs89x0, int addr, uint16_t value) -{ - /* In memory mode, the CS89x0's internal registers and frame buffers are mapped - * into a contiguous 4kb block providing direct access to the internal registers - * and frame buffers. - */ - -#ifdef CONFIG_CS89x0_MEMMODE - if (cs89x0->cs_memmode) - { -#ifdef CONFIG_CS89x0_ALIGN16 - putreg16(value), cs89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??)); -#else - putreg32((uint32_t)value, cs89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??)); -#endif - } - - /* When configured in I/O mode, the CS89x0 is accessed through eight, 16-bit - * I/O ports that in the host system's I/O space. - */ - - else -#endif - { -#ifdef CONFIG_CS89x0_ALIGN16 - putreg16((uint16_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET); - putreg16(value, cs89x0->cs_base + CS89x0_PDATA_OFFSET); -#else - putreg32((uint32_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET); - putreg32((uint32_t)value, cs89x0->cs_base + CS89x0_PDATA_OFFSET); -#endif - } -} - -/**************************************************************************** - * Function: cs89x0_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * cs89x0 - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int cs89x0_transmit(struct cs89x0_driver_s *cs89x0) -{ - /* Verify that the hardware is ready to send another packet */ -#warning "Missing logic" - - /* Increment statistics */ -#warning "Missing logic" - - /* Disable Ethernet interrupts */ -#warning "Missing logic" - - /* Send the packet: address=cs89x0->cs_dev.d_buf, length=cs89x0->cs_dev.d_len */ -#warning "Missing logic" - - /* Restore Ethernet interrupts */ -#warning "Missing logic" - - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - - (void)wd_start(cs89x0->cs_txtimeout, CS89x0_TXTIMEOUT, cs89x0_txtimeout, 1, (uint32_t)cs89x0); - return OK; -} - -/**************************************************************************** - * Function: cs89x0_uiptxpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from uip_poll(). uip_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int cs89x0_uiptxpoll(struct uip_driver_s *dev) -{ - struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (cs89x0->cs_dev.d_len > 0) - { - uip_arp_out(&cs89x0->cs_dev); - cs89x0_transmit(cs89x0); - - /* Check if there is room in the CS89x0 to hold another packet. If not, - * return a non-zero value to terminate the poll. - */ -#warning "Missing logic" - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: cs89x0_receive - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * cs89x0 - Reference to the driver state structure - * isq - Interrupt status queue value read by interrupt handler - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void cs89x0_receive(struct cs89x0_driver_s *cs89x0, uint16_t isq) -{ - uint16_t *dest; - uint16_t rxlength; - int nbytes; - - /* Check for errors and update statistics */ - - rxlength = cs89x0_getreg(PPR_RXLENGTH); - if ((isq & RX_OK) == 0) - { -#ifdef CONFIG_C89x0_STATISTICS - cd89x0->cs_stats.rx_errors++; - if ((isq & RX_RUNT) != 0) - { - cd89x0->cs_stats.rx_lengtherrors++; - } - if ((isq & RX_EXTRA_DATA) != 0) - { - cd89x0->cs_stats.rx_lengtherrors++; - } - if (isq & RX_CRC_ERROR) != 0) - { - if (!(isq & (RX_EXTRA_DATA|RX_RUNT))) - { - cd89x0->cs_stats.rx_crcerrors++; - } - } - if ((isq & RX_DRIBBLE) != 0) - { - cd89x0->cs_stats.rx_frameerrors++; - } -#endif - return; - } - - /* Check if the packet is a valid size for the uIP buffer configuration */ - - if (rxlength > ???) - { -#ifdef CONFIG_C89x0_STATISTICS - cd89x0->cs_stats.rx_errors++; - cd89x0->cs_stats.rx_lengtherrors++; -#endif - return; - } - - /* Copy the data data from the hardware to cs89x0->cs_dev.d_buf. Set - * amount of data in cs89x0->cs_dev.d_len - */ - - dest = (uint16_t*)cs89x0->cs_dev.d_buf; - for (nbytes = 0; nbytes < rxlength; nbytes += sizeof(uint16_t)) - { - *dest++ = cs89x0_getreg(PPR_RXFRAMELOCATION); - } - -#ifdef CONFIG_C89x0_STATISTICS - cd89x0->cs_stats.rx_packets++; -#endif - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(UIP_ETHTYPE_IP6)) -#else - if (BUF->type == HTONS(UIP_ETHTYPE_IP)) -#endif - { - uip_arp_ipin(&cs89x0->cs_dev); - uip_input(&cs89x0->cs_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (cs89x0->cs_dev.d_len > 0) - { - uip_arp_out(&cs89x0->cs_dev); - cs89x0_transmit(cs89x0); - } - } - else if (BUF->type == htons(UIP_ETHTYPE_ARP)) - { - uip_arp_arpin(&cs89x0->cs_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (cs89x0->cs_dev.d_len > 0) - { - cs89x0_transmit(cs89x0); - } - } -} - -/**************************************************************************** - * Function: cs89x0_txdone - * - * Description: - * An interrupt was received indicating that the last TX packet(s) is done - * - * Parameters: - * cs89x0 - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void cs89x0_txdone(struct cs89x0_driver_s *cs89x0, uint16_t isq) -{ - /* Check for errors and update statistics. The lower 6-bits of the ISQ - * hold the register address causing the interrupt. We got here because - * those bits indicated */ - -#ifdef CONFIG_C89x0_STATISTICS - cd89x0->cs_stats.tx_packets++; - if ((isq & ISQ_TXEVENT_TXOK) == 0) - { - cd89x0->cs_stats.tx_errors++; - } - if ((isq & ISQ_TXEVENT_LOSSOFCRS) != 0) - { - cd89x0->cs_stats.tx_carriererrors++; - } - if ((isq & ISQ_TXEVENT_SQEERROR) != 0) - { - cd89x0->cs_stats.tx_heartbeaterrors++; - } - if (i(sq & ISQ_TXEVENT_OUTWINDOW) != 0) - { - cd89x0->cs_stats.tx_windowerrors++; - } - if (isq & TX_16_COL) - { - cd89x0->cs_stats.tx_abortederrors++; - } -#endif - - /* If no further xmits are pending, then cancel the TX timeout */ - - wd_cancel(cs89x0->cs_txtimeout); - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&cs89x0->cs_dev, cs89x0_uiptxpoll); -} - -/**************************************************************************** - * Function: cs89x0_mapirq - * - * Description: - * Map an IRQ number to a CS89x0 device state instance. This is only - * necessary to handler the case where the architecture includes more than - * on CS89x0 chip. - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * - * Returned Value: - * A reference to device state structure (NULL if irq does not correspond - * to any CS89x0 device). - * - * Assumptions: - * - ****************************************************************************/ - -#if CONFIG_CS89x0_NINTERFACES > 1 -static inline FAR struct cs89x0_driver_s *cs89x0_mapirq(int irq) -{ - int i; - for (i = 0; i < CONFIG_CS89x0_NINTERFACES; i++) - { - if (g_cs89x0[i] && g_cs89x0[i].irq == irq) - { - return g_cs89x0[i]; - } - } - return NULL; -} -#endif - -/**************************************************************************** - * Function: cs89x0_interrupt - * - * Description: - * Hardware interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int cs89x0_interrupt(int irq, FAR void *context) -{ - register struct cs89x0_driver_s *cs89x0 = s89x0_mapirq(irq); - uint16_t isq; - -#ifdef CONFIG_DEBUG - if (!cs89x0) - { - return -ENODEV; - } -#endif - - /* Read and process all of the events from the ISQ */ - - while ((isq = cs89x0_getreg(dev, CS89x0_ISQ_OFFSET)) != 0) - { - nvdbg("ISQ: %04x\n", isq); - switch (isq & ISQ_EVENTMASK) - { - case ISQ_RXEVENT: - cs89x0_receive(cs89x0); - break; - - case ISQ_TXEVENT: - cs89x0_txdone(cs89x0, isq); - break; - - case ISQ_BUFEVENT: - if ((isq & ISQ_BUFEVENT_TXUNDERRUN) != 0) - { - ndbg("Transmit underrun\n"); -#ifdef CONFIG_CS89x0_XMITEARLY - cd89x0->cs_txunderrun++; - if (cd89x0->cs_txunderrun == 3) - { - cd89x0->cs_txstart = PPR_TXCMD_TXSTART381; - } - else if (cd89x0->cs_txunderrun == 6) - { - cd89x0->cs_txstart = PPR_TXCMD_TXSTARTFULL; - } -#endif - } - break; - - case ISQ_RXMISSEVENT: -#ifdef CONFIG_C89x0_STATISTICS - cd89x0->cs_stats.rx_missederrors += (isq >>6); -#endif - break; - - case ISQ_TXCOLEVENT: -#ifdef CONFIG_C89x0_STATISTICS - cd89x0->cs_stats.collisions += (isq >>6); -#endif - break; - } - } - return OK; -} - -/**************************************************************************** - * Function: cs89x0_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void cs89x0_txtimeout(int argc, uint32_t arg, ...) -{ - struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)arg; - - /* Increment statistics and dump debug info */ -#warning "Missing logic" - - /* Then reset the hardware */ -#warning "Missing logic" - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&cs89x0->cs_dev, cs89x0_uiptxpoll); -} - -/**************************************************************************** - * Function: cs89x0_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void cs89x0_polltimer(int argc, uint32_t arg, ...) -{ - struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)arg; - - /* Check if there is room in the send another TXr packet. */ -#warning "Missing logic" - - /* If so, update TCP timing states and poll uIP for new XMIT data */ - - (void)uip_timer(&cs89x0->cs_dev, cs89x0_uiptxpoll, CS89x0_POLLHSEC); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(cs89x0->cs_txpoll, CS89x0_WDDELAY, cs89x0_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: cs89x0_ifup - * - * Description: - * NuttX Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int cs89x0_ifup(struct uip_driver_s *dev) -{ - struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private; - - ndbg("Bringing up: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Initialize the Ethernet interface */ -#warning "Missing logic" - - /* Set and activate a timer process */ - - (void)wd_start(cs89x0->cs_txpoll, CS89x0_WDDELAY, cs89x0_polltimer, 1, (uint32_t)cs89x0); - - /* Enable the Ethernet interrupt */ - - cs89x0->cs_bifup = true; - up_enable_irq(CONFIG_CS89x0_IRQ); - return OK; -} - -/**************************************************************************** - * Function: cs89x0_ifdown - * - * Description: - * NuttX Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int cs89x0_ifdown(struct uip_driver_s *dev) -{ - struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - up_disable_irq(CONFIG_CS89x0_IRQ); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(cs89x0->cs_txpoll); - wd_cancel(cs89x0->cs_txtimeout); - - /* Reset the device */ - - cs89x0->cs_bifup = false; - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: cs89x0_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int cs89x0_txavail(struct uip_driver_s *dev) -{ - struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private; - irqstate_t flags; - - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (cs89x0->cs_bifup) - { - /* Check if there is room in the hardware to hold another outgoing packet. */ -#warning "Missing logic" - - /* If so, then poll uIP for new XMIT data */ - - (void)uip_poll(&cs89x0->cs_dev, cs89x0_uiptxpoll); - } - - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: cs89x0_addmac - * - * Description: - * NuttX Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int cs89x0_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct cs89x0_driver_s *priv = (FAR struct cs89x0_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - return OK; -} -#endif - -/**************************************************************************** - * Function: cs89x0_rmmac - * - * Description: - * NuttX Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int cs89x0_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct cs89x0_driver_s *priv = (FAR struct cs89x0_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: cs89x0_initialize - * - * Description: - * Initialize the Ethernet driver - * - * Parameters: - * impl - decribes the implementation of the cs89x00 implementation. - * This reference is retained so so must remain stable throughout the - * life of the driver instance. - * devno - Identifies the device number. This must be a number between - * zero CONFIG_CS89x0_NINTERFACES and the same devno must not be - * initialized twice. The associated network device will be referred - * to with the name "eth" followed by this number (eth0, eth1, etc). - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -/* Initialize the CS89x0 chip and driver */ - -int cs89x0_initialize(FAR const cs89x0_driver_s *cs89x0, int devno) -{ - /* Sanity checks -- only performed with debug enabled */ - -#ifdef CONFIG_DEBUG - if (!cs89x0 || (unsigned)devno > CONFIG_CS89x0_NINTERFACES || g_cs89x00[devno]) - { - return -EINVAL; - } -#endif - - /* Check if a Ethernet chip is recognized at its I/O base */ - -#warning "Missing logic" - - /* Attach the IRQ to the driver */ - - if (irq_attach(cs89x0->irq, cs89x0_interrupt)) - { - /* We could not attach the ISR to the ISR */ - - return -EAGAIN; - } - - /* Initialize the driver structure */ - - g_cs89x[devno] = cs89x0; /* Used to map IRQ back to instance */ - cs89x0->cs_dev.d_ifup = cs89x0_ifup; /* I/F down callback */ - cs89x0->cs_dev.d_ifdown = cs89x0_ifdown; /* I/F up (new IP address) callback */ - cs89x0->cs_dev.d_txavail = cs89x0_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - cs89x0->cs_dev.d_addmac = cs89x0_addmac; /* Add multicast MAC address */ - cs89x0->cs_dev.d_rmmac = cs89x0_rmmac; /* Remove multicast MAC address */ -#endif - cs89x0->cs_dev.d_private = (void*)cs89x0; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - cs89x0->cs_txpoll = wd_create(); /* Create periodic poll timer */ - cs89x0->cs_txtimeout = wd_create(); /* Create TX timeout timer */ - - /* Read the MAC address from the hardware into cs89x0->cs_dev.d_mac.ether_addr_octet */ - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - (void)netdev_register(&cs89x0->cs_dev); - return OK; -} - -#endif /* CONFIG_NET && CONFIG_NET_CS89x0 */ - diff --git a/nuttx/drivers/net/cs89x0.h b/nuttx/drivers/net/cs89x0.h deleted file mode 100644 index f6d99120a..000000000 --- a/nuttx/drivers/net/cs89x0.h +++ /dev/null @@ -1,326 +0,0 @@ -/**************************************************************************** - * drivers/net/cs89x0.h - * - * Copyright (C) 2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_NET_CS89x0_H -#define __DRIVERS_NET_CS89x0_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* CONFIG_CS89x0_ALIGN16/32 determines if the 16-bit CS89x0 registers are - * aligned to 16-bit or 32-bit address boundaries. NOTE: If there multiple - * CS89x00 parts in the board architecture, we assume that the address - * alignment is the same for all implementations. If that is not the - * case, then it will be necessary to move a shift value into - * the cs89x0_driver_s structure and calculate the offsets dynamically in - * the putreg and getreg functions. - */ - -#if defined(CONFIG_CS89x0_ALIGN16) -# define CS89x0_RTDATA_OFFSET (0 << 1) -# define CS89x0_TxCMD_OFFSET (2 << 1) -# define CS89x0_TxLEN_OFFSET (3 << 1) -# define CS89x0_ISQ_OFFSET (4 << 1) -# define CS89x0_PPTR_OFFSET (5 << 1) -# define CS89x0_PDATA_OFFSET (6 << 1) -#elif defined(CONFIG_CS89x0_ALIGN32) -# define CS89x0_RTDATA_OFFSET (0 << 2) -# define CS89x0_TxCMD_OFFSET (2 << 2) -# define CS89x0_TxLEN_OFFSET (3 << 2) -# define CS89x0_ISQ_OFFSET (4 << 2) -# define CS89x0_PPTR_OFFSET (5 << 2) -# define CS89x0_PDATA_OFFSET (6 << 2) -#else -# error "CS89x00 address alignment is not defined" -#endif - -/* ISQ register bit definitions */ - -#define ISQ_EVENTMASK 0x003f /* Bits 0-5 indicate the status register */ -#define ISQ_RXEVENT 0x0004 -#define ISQ_TXEVENT 0x0008 -#define ISQ_BUFEVENT 0x000c -#define ISQ_RXMISSEVENT 0x0010 -#define ISQ_TXCOLEVENT 0x0012 - -/* ISQ register TxEVENT bit definitions*/ - -#define ISQ_RXEVENT_IAHASH (1 << 6) -#define ISQ_RXEVENT_DRIBBLE (1 << 7) -#define ISQ_RXEVENT_RXOK (1 << 8) -#define ISQ_RXEVENT_HASHED (1 << 9) -#define ISQ_RXEVENT_HASHNDX_SHIFT 10 -#define ISQ_RXEVENT_HASHNDX_MASK (0x3f << ISQ_RXEVENT_HASHNDX_SHIFT) - -/* ISQ register TxEVENT bit definitions*/ - -#define ISQ_TXEVENT_LOSSOFCRS (1 << 6) -#define ISQ_TXEVENT_SQEERROR (1 << 7) -#define ISQ_TXEVENT_TXOK (1 << 8) -#define ISQ_TXEVENT_OUTWINDOW (1 << 9) -#define ISQ_TXEVENT_JABBER (1 << 10) -#define ISQ_TXEVENT_NCOLLISION_SHIFT 11 -#define ISQ_TXEVENT_NCOLLISION_MASK (15 << ISQ_TXEVENT_NCOLLISION_SHIFT) -#define ISQ_TXEVENT_16COLL (1 << 15) - -/* ISQ register BufEVENT bit definitions */ - -#define ISQ_BUFEVENT_SWINT (1 << 6) -#define ISQ_BUFEVENT_RXDMAFRAME (1 << 7) -#define ISQ_BUFEVENT_RDY4TX (1 << 8) -#define ISQ_BUFEVENT_TXUNDERRUN (1 << 9) -#define ISQ_BUFEVENT_RXMISS (1 << 10) -#define ISQ_BUFEVENT_RX128 (1 << 11) -#define ISQ_BUFEVENT_RXDEST (1 << 15) - -/* Packet page register offsets *********************************************/ - -/* 0x0000 Bus interface registers */ - -#define PPR_CHIPID 0x0000 /* Chip identifier - must be 0x630E */ -#define PPR_CHIPREV 0x0002 /* Chip revision, model codes */ -#define PPR_IOBASEADDRESS 0x0020 /* I/O Base Address */ -#define PPR_INTREG 0x0022 /* Interrupt configuration */ -# define PPR_INTREG_IRQ0 0x0000 /* Use INTR0 pin */ -# define PPR_INTREG_IRQ1 0x0001 /* Use INTR1 pin */ -# define PPR_INTREG_IRQ2 0x0002 /* Use INTR2 pin */ -# define PPR_INTREG_IRQ3 0x0003 /* Use INTR3 pin */ - -#define PPR_DMACHANNELNUMBER 0x0024 /* DMA Channel Number (0,1, or 2) */ -#define PPR_DMASTARTOFFRAME 0x0026 /* DMA Start of Frame */ -#define PPR_DMAFRAMECOUNT 0x0028 /* DMA Frame Count (12-bits) */ -#define PPR_RXDMABYTECOUNT 0x002a /* Rx DMA Byte Count */ -#define PPR_MEMORYBASEADDRESS 0x002c /* Memory Base Address Register (20-bit) */ -#define PPR_BOOTPROMBASEADDRESS 0x0030 /* Boot PROM Base Address */ -#define PPR_BOOTPROMADDRESSMASK 0x0034 /* Boot PROM Address Mask */ -#define PPR_EEPROMCOMMAND 0x0040 /* EEPROM Command */ -#define PPR_EEPROMDATA 0x0042 /* EEPROM Data */ -#define PPR_RECVFRAMEBYTES 0x0050 /* Received Frame Byte Counter */ - -/* 0x0100 - Configuration and control registers */ - -#define PPR_RXCFG 0x0102 /* Receiver configuration */ -# define PPR_RXCFG_SKIP1 (1 << 6) /* Skip (discard) current frame */ -# define PPR_RXCFG_STREAM (1 << 7) /* Enable streaming mode */ -# define PPR_RXCFG_RXOK (1 << 8) /* RxOK interrupt enable */ -# define PPR_RxCFG_RxDMAonly (1 << 9) /* Use RxDMA for all frames */ -# define PPR_RxCFG_AutoRxDMA (1 << 10) /* Select RxDMA automatically */ -# define PPR_RxCFG_BufferCRC (1 << 11) /* Include CRC characters in frame */ -# define PPR_RxCFG_CRC (1 << 12) /* Enable interrupt on CRC error */ -# define PPR_RxCFG_RUNT (1 << 13) /* Enable interrupt on RUNT frames */ -# define PPR_RxCFG_EXTRA (1 << 14) /* Enable interrupt on frames with extra data */ - -#define PPR_RXCTL 0x0104 /* Receiver control */ -# define PPR_RXCTL_IAHASH (1 << 6) /* Accept frames that match hash */ -# define PPR_RXCTL_PROMISCUOUS (1 << 7) /* Accept any frame */ -# define PPR_RXCTL_RXOK (1 << 8) /* Accept well formed frames */ -# define PPR_RXCTL_MULTICAST (1 << 9) /* Accept multicast frames */ -# define PPR_RXCTL_IA (1 << 10) /* Accept frame that matches IA */ -# define PPR_RXCTL_BROADCAST (1 << 11) /* Accept broadcast frames */ -# define PPR_RXCTL_CRC (1 << 12) /* Accept frames with bad CRC */ -# define PPR_RXCTL_RUNT (1 << 13) /* Accept runt frames */ -# define PPR_RXCTL_EXTRA (1 << 14) /* Accept frames that are too long */ - -#define PPR_TXCFG 0x0106 /* Transmit configuration */ -# define PPR_TXCFG_CRS (1 << 6) /* Enable interrupt on loss of carrier */ -# define PPR_TXCFG_SQE (1 << 7) /* Enable interrupt on Signal Quality Error */ -# define PPR_TXCFG_TXOK (1 << 8) /* Enable interrupt on successful xmits */ -# define PPR_TXCFG_LATE (1 << 9) /* Enable interrupt on "out of window" */ -# define PPR_TXCFG_JABBER (1 << 10) /* Enable interrupt on jabber detect */ -# define PPR_TXCFG_COLLISION (1 << 11) /* Enable interrupt if collision */ -# define PPR_TXCFG_16COLLISIONS (1 << 15) /* Enable interrupt if > 16 collisions */ - -#define PPR_TXCMD 0x0108 /* Transmit command status */ -# define PPR_TXCMD_TXSTART5 (0 << 6) /* Start after 5 bytes in buffer */ -# define PPR_TXCMD_TXSTART381 (1 << 6) /* Start after 381 bytes in buffer */ -# define PPR_TXCMD_TXSTART1021 (2 << 6) /* Start after 1021 bytes in buffer */ -# define PPR_TXCMD_TXSTARTFULL (3 << 6) /* Start after all bytes loaded */ -# define PPR_TXCMD_FORCE (1 << 8) /* Discard any pending packets */ -# define PPR_TXCMD_ONECOLLISION (1 << 9) /* Abort after a single collision */ -# define PPR_TXCMD_NOCRC (1 << 12) /* Do not add CRC */ -# define PPR_TXCMD_NOPAD (1 << 13) /* Do not pad short packets */ - -#define PPR_BUFCFG 0x010a /* Buffer configuration */ -# define PPR_BUFCFG_SWI (1 << 6) /* Force interrupt via software */ -# define PPR_BUFCFG_RXDMA (1 << 7) /* Enable interrupt on Rx DMA */ -# define PPR_BUFCFG_TXRDY (1 << 8) /* Enable interrupt when ready for Tx */ -# define PPR_BUFCFG_TXUE (1 << 9) /* Enable interrupt in Tx underrun */ -# define PPR_BUFCFG_RXMISS (1 << 10) /* Enable interrupt on missed Rx packets */ -# define PPR_BUFCFG_RX128 (1 << 11) /* Enable Rx interrupt after 128 bytes */ -# define PPR_BUFCFG_TXCOL (1 << 12) /* Enable int on Tx collision ctr overflow */ -# define PPR_BUFCFG_MISS (1 << 13) /* Enable int on Rx miss ctr overflow */ -# define PPR_BUFCFG_RXDEST (1 << 15) /* Enable int on Rx dest addr match */ - -#define PPR_LINECTL 0x0112 /* Line control */ -# define PPR_LINECTL_RX (1 << 6) /* Enable receiver */ -# define PPR_LINECTL_TX (1 << 7) /* Enable transmitter */ -# define PPR_LINECTL_AUIONLY (1 << 8) /* AUI interface only */ -# define PPR_LINECTL_AUTOAUI10BT (1 << 9) /* Autodetect AUI or 10BaseT interface */ -# define PPR_LINECTL_MODBACKOFFE (1 << 11) /* Enable modified backoff algorithm */ -# define PPR_LINECTL_POLARITYDIS (1 << 12) /* Disable Rx polarity autodetect */ -# define PPR_LINECTL_2PARTDEFDIS (1 << 13) /* Disable two-part defferal */ -# define PPR_LINECTL_LORXSQUELCH (1 << 14) /* Reduce receiver squelch threshold */ - -#define PPR_SELFCTL 0x0114 /* Chip self control */ -# define PPR_SELFCTL_RESET (1 << 6) /* Self-clearing reset */ -# define PPR_SELFCTL_SWSUSPEND (1 << 8) /* Initiate suspend mode */ -# define PPR_SELFCTL_HWSLEEPE (1 << 9) /* Enable SLEEP input */ -# define PPR_SELFCTL_HWSTANDBYE (1 << 10) /* Enable standby mode */ -# define PPR_SELFCTL_HC0E (1 << 12) /* Use HCB0 for LINK LED */ -# define PPR_SELFCTL_HC1E (1 << 13) /* Use HCB1 for BSTATUS LED */ -# define PPR_SELFCTL_HCB0 (1 << 14) /* Control LINK LED if HC0E set */ -# define PPR_SELFCTL_HCB1 (1 << 15) /* Cntrol BSTATUS LED if HC1E set */ - -#define PPR_BUSCTL 0x0116 /* Bus control */ -# define PPR_BUSCTL_RESETRXDMA (1 << 6) /* Reset RxDMA pointer */ -# define PPR_BUSCTL_DMAEXTEND (1 << 8) /* Extend DMA cycle */ -# define PPR_BUSCTL_USESA (1 << 9) /* Assert MEMCS16 on address decode */ -# define PPR_BUSCTL_MEMORYE (1 << 10) /* Enable memory mode */ -# define PPR_BUSCTL_DMABURST (1 << 11) /* Limit DMA access burst */ -# define PPR_BUSCTL_IOCHRDYE (1 << 12) /* Set IOCHRDY high impedence */ -# define PPR_BUSCTL_RXDMASIZE (1 << 13) /* Set DMA buffer size 64KB */ -# define PPR_BUSCTL_ENABLEIRQ (1 << 15) /* Generate interrupt on interrupt event */ - -#define PPR_TESTCTL 0x0118 /* Test control */ -# define PPR_TESTCTL_DISABLELT (1 << 7) /* Disable link status */ -# define PPR_TESTCTL_ENDECLOOP (1 << 9) /* Internal loopback */ -# define PPR_TESTCTL_AUILOOP (1 << 10) /* AUI loopback */ -# define PPR_TESTCTL_DISBACKOFF (1 << 11) /* Disable backoff algorithm */ -# define PPR_TESTCTL_FDX (1 << 14) /* Enable full duplex mode */ - -/* 0x0120 - Status and Event Registers */ - -#define PPR_ISQ 0x0120 /* Interrupt Status Queue */ -#define PPR_RER 0x0124 /* Receive event */ -# define PPR_RER_IAHASH (1 << 6) /* Frame hash match */ -# define PPR_RER_DRIBBLE (1 << 7) /* Frame had 1-7 extra bits after last byte */ -# define PPR_RER_RXOK (1 << 8) /* Frame received with no errors */ -# define PPR_RER_HASHED (1 << 9) /* Frame address hashed OK */ -# define PPR_RER_IA (1 << 10) /* Frame address matched IA */ -# define PPR_RER_BROADCAST (1 << 11) /* Broadcast frame */ -# define PPR_RER_CRC (1 << 12) /* Frame had CRC error */ -# define PPR_RER_RUNT (1 << 13) /* Runt frame */ -# define PPR_RER_EXTRA (1 << 14) /* Frame was too long */ - -#define PPR_TER 0x0128 /* Transmit event */ -# define PPR_TER_CRS (1 << 6) /* Carrier lost */ -# define PPR_TER_SQE (1 << 7) /* Signal Quality Error */ -# define PPR_TER_TXOK (1 << 8) /* Packet sent without error */ -# define PPR_TER_LATE (1 << 9) /* Out of window */ -# define PPR_TER_JABBER (1 << 10) /* Stuck transmit? */ -# define PPR_TER_NUMCOLLISIONS_SHIFT 11 -# define PPR_TER_NUMCOLLISIONS_MASK (15 << PPR_TER_NUMCOLLISIONS_SHIFT) -# define PPR_TER_16COLLISIONS (1 << 15) /* > 16 collisions */ - -#define PPR_BER 0x012C /* Buffer event */ -# define PPR_BER_SWINT (1 << 6) /* Software interrupt */ -# define PPR_BER_RXDMAFRAME (1 << 7) /* Received framed DMAed */ -# define PPR_BER_RDY4TX (1 << 8) /* Ready for transmission */ -# define PPR_BER_TXUNDERRUN (1 << 9) /* Transmit underrun */ -# define PPR_BER_RXMISS (1 << 10) /* Received frame missed */ -# define PPR_BER_RX128 (1 << 11) /* 128 bytes received */ -# define PPR_BER_RXDEST (1 << 15) /* Received framed passed address filter */ - -#define PPR_RXMISS 0x0130 /* Receiver miss counter */ -#define PPR_TXCOL 0x0132 /* Transmit collision counter */ -#define PPR_LINESTAT 0x0134 /* Line status */ -# define PPR_LINESTAT_LINKOK (1 << 7) /* Line is connected and working */ -# define PPR_LINESTAT_AUI (1 << 8) /* Connected via AUI */ -# define PPR_LINESTAT_10BT (1 << 9) /* Connected via twisted pair */ -# define PPR_LINESTAT_POLARITY (1 << 12) /* Line polarity OK (10BT only) */ -# define PPR_LINESTAT_CRS (1 << 14) /* Frame being received */ - -#define PPR_SELFSTAT 0x0136 /* Chip self status */ -# define PPR_SELFSTAT_33VACTIVE (1 << 6) /* supply voltage is 3.3V */ -# define PPR_SELFSTAT_INITD (1 << 7) /* Chip initialization complete */ -# define PPR_SELFSTAT_SIBSY (1 << 8) /* EEPROM is busy */ -# define PPR_SELFSTAT_EEPROM (1 << 9) /* EEPROM present */ -# define PPR_SELFSTAT_EEPROMOK (1 << 10) /* EEPROM checks out */ -# define PPR_SELFSTAT_ELPRESENT (1 << 11) /* External address latch logic available */ -# define PPR_SELFSTAT_EESIZE (1 << 12) /* Size of EEPROM */ - -#define PPR_BUSSTAT 0x0138 /* Bus status */ -# define PPR_BUSSTAT_TXBID (1 << 7) /* Tx error */ -# define PPR_BUSSTAT_TXRDY (1 << 8) /* Ready for Tx data */ - -#define PPR_TDR 0x013C /* AUI Time Domain Reflectometer */ - -/* 0x0144 - Initiate transmit registers */ - -#define PPR_TXCOMMAND 0x0144 /* Tx Command */ -#define PPR_TXLENGTH 0x0146 /* Tx Length */ - -/* 0x0150 - Address filter registers */ - -#define PPR_LAF 0x0150 /* Logical address filter (6 bytes) */ -#define PPR_IA 0x0158 /* Individual address (MAC) */ - -/* 0x0400 - Frame location registers */ - -#define PPR_RXSTATUS 0x0400 /* Rx Status */ -#define PPR_RXLENGTH 0x0402 /* Rx Length */ -#define PPR_RXFRAMELOCATION 0x0404 /* Rx Frame Location */ -#define PPR_TXFRAMELOCATION 0x0a00 /* Tx Frame Location */ - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_NET_CS89x0_H */ diff --git a/nuttx/drivers/net/dm90x0.c b/nuttx/drivers/net/dm90x0.c deleted file mode 100644 index 2f5b26abb..000000000 --- a/nuttx/drivers/net/dm90x0.c +++ /dev/null @@ -1,1815 +0,0 @@ -/**************************************************************************** - * drivers/net/dm9x.c - * - * Copyright (C) 2007-2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: Davicom data sheets (DM9000-DS-F03-041906.pdf, - * DM9010-DS-F01-103006.pdf) and looking at lots of other DM90x0 - * drivers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#if defined(CONFIG_NET) && defined(CONFIG_NET_DM90x0) - -/* Only one hardware interface supported at present (although there are - * hooks throughout the design to that extending the support to multiple - * interfaces should not be that difficult) - */ - -#undef CONFIG_DM9X_NINTERFACES -#define CONFIG_DM9X_NINTERFACES 1 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* DM90000 and DM9010 register offets */ - -#define DM9X_NETC 0x00 /* Network control register */ -#define DM9X_NETS 0x01 /* Network Status register */ -#define DM9X_TXC 0x02 /* TX control register */ -#define DM9X_TXS1 0x03 /* TX status register 1 */ -#define DM9X_TXS2 0x03 /* TX status register 2 */ -#define DM9X_RXC 0x05 /* RX control register */ -#define DM9X_RXS 0x06 /* RX status register */ -#define DM9X_RXOVF 0x07 /* Receive overflow counter register */ -#define DM9X_BPTHRES 0x08 /* Back pressure threshold register */ -#define DM9X_FCTHRES 0x09 /* Flow control threshold register */ -#define DM9X_FC 0x0a /* RX/TX flow control register */ -#define DM9X_EEPHYC 0x0b /* EEPROM & PHY control register */ -#define DM9X_EEPHYA 0x0c /* EEPROM & PHY address register */ -#define DM9X_EEPHYDL 0x0d /* EEPROM & PHY data register (lo) */ -#define DM9X_EEPHYDH 0x0e /* EEPROM & PHY data register (hi) */ -#define DM9X_WAKEUP 0x0f /* Wake-up control register */ -#define DM9X_PAB0 0x10 /* Physical address register (byte 0) */ -#define DM9X_PAB1 0x11 /* Physical address register (byte 1) */ -#define DM9X_PAB2 0x12 /* Physical address register (byte 2) */ -#define DM9X_PAB3 0x13 /* Physical address register (byte 3) */ -#define DM9X_PAB4 0x14 /* Physical address register (byte 4) */ -#define DM9X_PAB5 0x15 /* Physical address register (byte 5) */ -#define DM9X_MAB0 0x16 /* Multicast address register (byte 0) */ -#define DM9X_MAB1 0x17 /* Multicast address register (byte 1) */ -#define DM9X_MAB2 0x18 /* Multicast address register (byte 2) */ -#define DM9X_MAB3 0x19 /* Multicast address register (byte 3) */ -#define DM9X_MAB4 0x1a /* Multicast address register (byte 4) */ -#define DM9X_MAB5 0x1b /* Multicast address register (byte 5) */ -#define DM9X_MAB6 0x1c /* Multicast address register (byte 6) */ -#define DM9X_MAB7 0x1d /* Multicast address register (byte 7) */ -#define DM9X_GPC 0x1e /* General purpose control register */ -#define DM9X_GPD 0x1f /* General purpose register */ - -#define DM9X_TRPAL 0x22 /* TX read pointer address (lo) */ -#define DM9X_TRPAH 0x23 /* TX read pointer address (hi) */ -#define DM9X_RWPAL 0x24 /* RX write pointer address (lo) */ -#define DM9X_RWPAH 0x25 /* RX write pointer address (hi) */ - -#define DM9X_VIDL 0x28 /* Vendor ID (lo) */ -#define DM9X_VIDH 0x29 /* Vendor ID (hi) */ -#define DM9X_PIDL 0x2a /* Product ID (lo) */ -#define DM9X_PIDH 0x2b /* Product ID (hi) */ -#define DM9X_CHIPR 0x2c /* Product ID (lo) */ -#define DM9X_TXC2 0x2d /* Transmit control register 2 (dm9010) */ -#define DM9X_OTC 0x2e /* Operation test control register (dm9010) */ -#define DM9X_SMODEC 0x2f /* Special mode control register */ -#define DM9X_ETXCSR 0x30 /* Early transmit control/status register (dm9010) */ -#define DM9X_TCCR 0x31 /* Transmit checksum control register (dm9010) */ -#define DM9X_RCSR 0x32 /* Receive checksum control/status register (dm9010) */ -#define DM9X_EPHYA 0x33 /* External PHY address register (dm9010) */ -#define DM9X_GPC2 0x34 /* General purpose control register 2 (dm9010) */ -#define DM9X_GPD2 0x35 /* General purpose register 2 */ -#define DM9X_GPC3 0x36 /* General purpose control register 3 (dm9010) */ -#define DM9X_GPD3 0x37 /* General purpose register 3 */ -#define DM9X_PBUSC 0x38 /* Processor bus control register (dm9010) */ -#define DM9X_IPINC 0x39 /* INT pin control register (dm9010) */ - -#define DM9X_MON1 0x40 /* Monitor register 1 (dm9010) */ -#define DM9X_MON2 0x41 /* Monitor register 2 (dm9010) */ - -#define DM9X_SCLKC 0x50 /* System clock turn ON control register (dm9010) */ -#define DM9X_SCLKR 0x51 /* Resume system clock control register (dm9010) */ - -#define DM9X_MRCMDX 0xf0 /* Memory data pre-fetch read command without address increment */ -#define DM9X_MRCMDX1 0xf1 /* memory data read command without address increment (dm9010) */ -#define DM9X_MRCMD 0xf2 /* Memory data read command with address increment */ -#define DM9X_MDRAL 0xf4 /* Memory data read address register (lo) */ -#define DM9X_MDRAH 0xf5 /* Memory data read address register (hi) */ -#define DM9X_MWCMDX 0xf6 /* Memory data write command without address increment */ -#define DM9X_MWCMD 0xf8 /* Memory data write command with address increment */ -#define DM9X_MDWAL 0xfa /* Memory data write address register (lo) */ -#define DM9X_MDWAH 0xfb /* Memory data write address register (lo) */ -#define DM9X_TXPLL 0xfc /* Memory data write address register (lo) */ -#define DM9X_TXPLH 0xfd /* Memory data write address register (hi) */ -#define DM9X_ISR 0xfe /* Interrupt status register */ -#define DM9X_IMR 0xff /* Interrupt mask register */ - -/* Network control register bit definitions */ - -#define DM9X_NETC_RST (1 << 0) /* Software reset */ -#define DM9X_NETC_LBKM (3 << 1) /* Loopback mode mask */ -#define DM9X_NETC_LBK0 (0 << 1) /* 0: Normal */ -#define DM9X_NETC_LBK1 (1 << 1) /* 1: MAC internal loopback */ -#define DM9X_NETC_LBK2 (2 << 1) /* 2: Internal PHY 100M mode loopback */ -#define DM9X_NETC_FDX (1 << 3) /* Full dupliex mode */ -#define DM9X_NETC_FCOL (1 << 4) /* Force collision mode */ -#define DM9X_NETC_WAKEEN (1 << 6) /* Wakeup event enable */ -#define DM9X_NETC_EXTPHY (1 << 7) /* Select external PHY */ - -/* Network status bit definitions */ - -#define DM9X_NETS_RXOV (1 << 1) /* RX Fifo overflow */ -#define DM9X_NETS_TX1END (1 << 2) /* TX packet 1 complete status */ -#define DM9X_NETS_TX2END (1 << 3) /* TX packet 2 complete status */ -#define DM9X_NETS_WAKEST (1 << 5) /* Wakeup event status */ -#define DM9X_NETS_LINKST (1 << 6) /* Link status */ -#define DM9X_NETS_SPEED (1 << 7) /* Media speed */ - -/* IMR/ISR bit definitions */ - -#define DM9X_INT_PR (1 << 0) /* Packet received interrupt */ -#define DM9X_INT_PT (1 << 1) /* Packet transmitted interrupt */ -#define DM9X_INT_RO (1 << 2) /* Receive overflow interrupt */ -#define DM9X_INT_ROO (1 << 3) /* Receive overflow counter overflow int */ -#define DM9X_INT_UDRUN (1 << 4) /* Transmit underrun interrupt */ -#define DM9X_INT_LNKCHG (1 << 5) /* Link status change interrupt */ -#define DM9X_INT_ALL (0x3f) - -#define DM9X_IMR_UNUSED (1 << 6) /* (not used) */ -#define DM9X_IMR_PAR (1 << 7) /* Enable auto R/W pointer reset */ - -#define DM9X_ISR_IOMODEM (3 << 6) /* IO mode mask */ -#define DM9X_ISR_IOMODE8 (2 << 6) /* IO mode = 8 bit */ -#define DM9X_ISR_IOMODE16 (0 << 6) /* IO mode = 16 bit */ -#define DM9X_ISR_IOMODE32 (1 << 6) /* IO mode = 32 bit */ - -#define DM9X_IMRENABLE (DM9X_INT_PR|DM9X_INT_PT|DM9X_INT_LNKCHG|DM9X_IMR_PAR) -#define DM9X_IMRRXDISABLE (DM9X_INT_PT|DM9X_INT_LNKCHG|DM9X_IMR_PAR) -#define DM9X_IMRDISABLE (DM9X_IMR_PAR) - -/* EEPROM/PHY control regiser bits */ - -#define DM9X_EEPHYC_ERRE (1 << 0) /* EEPROM (vs PHY) access status */ -#define DM9X_EEPHYC_ERPRW (1 << 1) /* EEPROM/PHY write access */ -#define DM9X_EEPHYC_ERPRR (1 << 2) /* EEPROM/PHY read access */ -#define DM9X_EEPHYC_EPOS (1 << 3) /* EEPROM/PHY operation select */ -#define DM9X_EEPHYC_WEP (1 << 4) /* Write EEPROM enable */ -#define DM9X_EEPHYC_REEP (1 << 5) /* Reload EEPROM */ - -/* Supported values from the vendor and product ID register */ - -#define DM9X_DAVICOMVID 0x0a46 -#define DM9X_DM9000PID 0x9000 -#define DM9X_DM9010PID 0x9010 - -/* RX control register bit settings */ - -#define DM9X_RXC_RXEN (1 << 0) /* RX enable */ -#define DM9X_RXC_PRMSC (1 << 1) /* Promiscuous mode */ -#define DM9X_RXC_RUNT (1 << 2) /* Pass runt packet */ -#define DM9X_RXC_ALL (1 << 3) /* Pass all multicast */ -#define DM9X_RXC_DISCRC (1 << 4) /* Discard CRC error packets */ -#define DM9X_RXC_DISLONG (1 << 5) /* Discard long packets */ -#define DM9X_RXC_WTDIS (1 << 6) /* Disable watchdog timer */ -#define DM9X_RXC_HASHALL (1 << 7) /* Filter all addresses in hash table */ - -#define DM9X_RXCSETUP (DM9X_RXC_DISCRC|DM9X_RXC_DISLONG) - -/* EEPHY bit settings */ - -#define DM9X_EEPHYA_EROA 0x40 /* PHY register address 0x01 */ - -#define DM9X_PKTRDY 0x01 /* Packet ready to receive */ - -/* The RX interrupt will be disabled if more than the following RX - * interrupts are received back-to-back. - */ - -#define DM9X_CRXTHRES 10 - -/* All access is via an index register and a data regist. Select accecss - * according to user supplied base address and bus width. - */ - -#if defined(CONFIG_DM9X_BUSWIDTH8) -# define DM9X_INDEX *(volatile uint8_t*)(CONFIG_DM9X_BASE) -# define DM9X_DATA *(volatile uint8_t*)(CONFIG_DM9X_BASE + 2) -#elif defined(CONFIG_DM9X_BUSWIDTH16) -# define DM9X_INDEX *(volatile uint16_t*)(CONFIG_DM9X_BASE) -# define DM9X_DATA *(volatile uint16_t*)(CONFIG_DM9X_BASE + 2) -#elif defined(CONFIG_DM9X_BUSWIDTH32) -# define DM9X_INDEX *(volatile uint32_t*)(CONFIG_DM9X_BASE) -# define DM9X_DATA *(volatile uint32_t*)(CONFIG_DM9X_BASE + 2) -#endif - -/* Phy operating mode. Default is AUTO, but this setting can be overridden - * in the NuttX configuration file. - */ - -#define DM9X_MODE_AUTO 0 -#define DM9X_MODE_10MHD 1 -#define DM9X_MODE_100MHD 2 -#define DM9X_MODE_10MFD 3 -#define DM9X_MODE_100MFD 4 - -#ifndef CONFIG_DM9X_MODE -# define CONFIG_DM9X_MODE DM9X_MODE_AUTO -#endif - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define DM6X_WDDELAY (1*CLK_TCK) -#define DM6X_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define DM6X_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct uip_eth_hdr *)dm9x->dm_dev.d_buf) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -union rx_desc_u -{ - uint8_t rx_buf[4]; - struct - { - uint8_t rx_byte; - uint8_t rx_status; - uint16_t rx_len; - } desc; -}; - -/* The dm9x_driver_s encapsulates all DM90x0 state information for a single - * DM90x0 hardware interface - */ - -struct dm9x_driver_s -{ - bool dm_bifup; /* true:ifup false:ifdown */ - bool dm_b100M; /* true:speed == 100M; false:speed == 10M */ - WDOG_ID dm_txpoll; /* TX poll timer */ - WDOG_ID dm_txtimeout; /* TX timeout timer */ - uint8_t dm_ntxpending; /* Count of packets pending transmission */ - uint8_t ncrxpackets; /* Number of continuous rx packets */ - - /* Mode-dependent function to move data in 8/16/32 I/O modes */ - - void (*dm_read)(uint8_t *ptr, int len); - void (*dm_write)(const uint8_t *ptr, int len); - void (*dm_discard)(int len); - -#if defined(CONFIG_DM9X_STATS) - uint32_t dm_ntxpackets; /* Count of packets sent */ - uint32_t dm_ntxbytes; /* Count of bytes sent */ - uint32_t dm_ntxerrors; /* Count of TX errors */ - uint32_t dm_nrxpackets; /* Count of packets received */ - uint32_t dm_nrxbytes; /* Count of bytes received */ - uint32_t dm_nrxfifoerrors; /* Count of RX FIFO overflow errors */ - uint32_t dm_nrxcrcerrors; /* Count of RX CRC errors */ - uint32_t dm_nrxlengtherrors; /* Count of RX length errors */ - uint32_t dm_nphyserrors; /* Count of physical layer errors */ - uint32_t dm_nresets; /* Counts number of resets */ - uint32_t dm_ntxtimeouts; /* Counts resets caused by TX timeouts */ -#endif - - /* This holds the information visible to uIP/NuttX */ - - struct uip_driver_s dm_dev; -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* At present, only a single DM90x0 device is supported. */ - -static struct dm9x_driver_s g_dm9x[CONFIG_DM9X_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Utility functions */ - -static uint8_t getreg(int reg); -static void putreg(int reg, uint8_t value); -static void read8(uint8_t *ptr, int len); -static void read16(uint8_t *ptr, int len); -static void read32(uint8_t *ptr, int len); -static void discard8(int len); -static void discard16(int len); -static void discard32(int len); -static void write8(const uint8_t *ptr, int len); -static void write16(const uint8_t *ptr, int len); -static void write32(const uint8_t *ptr, int len); - -/* static uint16_t dm9x_readsrom(struct dm9x_driver_s *dm9x, int offset); */ -static uint16_t dm9x_phyread(struct dm9x_driver_s *dm9x, int reg); -static void dm9x_phywrite(struct dm9x_driver_s *dm9x, int reg, uint16_t value); - -#if defined(CONFIG_DM9X_STATS) -static void dm9x_resetstatistics(struct dm9x_driver_s *dm9x); -#else -# define dm9x_resetstatistics(dm9x) -#endif - -#if defined(CONFIG_DM9X_STATS) && defined(CONFIG_DEBUG) -static void dm9x_dumpstatistics(struct dm9x_driver_s *dm9x); -#else -# define dm9x_dumpstatistics(dm9x) -#endif - -#if defined(CONFIG_DM9X_CHECKSUM) -static bool dm9x_rxchecksumready(uint8_t); -#else -# define dm9x_rxchecksumready(a) ((a) == 0x01) -#endif - -/* Common TX logic */ - -static int dm9x_transmit(struct dm9x_driver_s *dm9x); -static int dm9x_uiptxpoll(struct uip_driver_s *dev); - -/* Interrupt handling */ - -static void dm9x_receive(struct dm9x_driver_s *dm9x); -static void dm9x_txdone(struct dm9x_driver_s *dm9x); -static int dm9x_interrupt(int irq, FAR void *context); - -/* Watchdog timer expirations */ - -static void dm9x_polltimer(int argc, uint32_t arg, ...); -static void dm9x_txtimeout(int argc, uint32_t arg, ...); - -/* NuttX callback functions */ - -static int dm9x_ifup(struct uip_driver_s *dev); -static int dm9x_ifdown(struct uip_driver_s *dev); -static int dm9x_txavail(struct uip_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int dm9x_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -static int dm9x_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -#endif - -/* Initialization functions */ - -static void dm9x_bringup(struct dm9x_driver_s *dm9x); -static void dm9x_reset(struct dm9x_driver_s *dm9x); - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: getreg and setreg - * - * Description: - * Access to memory-mapped DM90x0 8-bit registers - * - * Parameters: - * reg - Register number - * value - Value to write to the register (setreg only) - * - * Returned Value: - * Value read from the register (getreg only) - * - * Assumptions: - * - ****************************************************************************/ - -static uint8_t getreg(int reg) -{ - DM9X_INDEX = reg; - return DM9X_DATA & 0xff; -} - -static void putreg(int reg, uint8_t value) -{ - DM9X_INDEX = reg; - DM9X_DATA = value & 0xff; -} - -/**************************************************************************** - * Function: read8, read16, read32 - * - * Description: - * Read packet data from the DM90x0 SRAM based on its current I/O mode - * - * Parameters: - * ptr - Location to write the packet data - * len - The number of bytes to read - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void read8(uint8_t *ptr, int len) -{ - nvdbg("Read %d bytes (8-bit mode)\n", len); - for (; len > 0; len--) - { - *ptr++ = DM9X_DATA; - } -} - -static void read16(uint8_t *ptr, int len) -{ - register uint16_t *ptr16 = (uint16_t*)ptr; - nvdbg("Read %d bytes (16-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint16_t)) - { - *ptr16++ = DM9X_DATA; - } -} - -static void read32(uint8_t *ptr, int len) -{ - register uint32_t *ptr32 = (uint32_t*)ptr; - nvdbg("Read %d bytes (32-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint32_t)) - { - *ptr32++ = DM9X_DATA; - } -} - -/**************************************************************************** - * Function: discard8, discard16, discard32 - * - * Description: - * Read and discard packet data in the DM90x0 SRAM based on its current - * I/O mode - * - * Parameters: - * len - The number of bytes to discard - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void discard8(int len) -{ - nvdbg("Discard %d bytes (8-bit mode)\n", len); - for (; len > 0; len--) - { - DM9X_DATA; - } -} - -static void discard16(int len) -{ - nvdbg("Discard %d bytes (16-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint16_t)) - { - DM9X_DATA; - } -} - -static void discard32(int len) -{ - nvdbg("Discard %d bytes (32-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint32_t)) - { - DM9X_DATA; - } -} - -/**************************************************************************** - * Function: write8, write16, write32 - * - * Description: - * Write packet data into the DM90x0 SRAM based on its current I/O mode - * - * Parameters: - * ptr - Location to write the packet data - * len - The number of bytes to read - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void write8(const uint8_t *ptr, int len) -{ - nvdbg("Write %d bytes (8-bit mode)\n", len); - for (; len > 0; len--) - { - DM9X_DATA = (*ptr++ & 0xff); - } -} - -static void write16(const uint8_t *ptr, int len) -{ - register uint16_t *ptr16 = (uint16_t*)ptr; - nvdbg("Write %d bytes (16-bit mode)\n", len); - - for (; len > 0; len -= sizeof(uint16_t)) - { - DM9X_DATA = *ptr16++; - } -} - -static void write32(const uint8_t *ptr, int len) -{ - register uint32_t *ptr32 = (uint32_t*)ptr; - nvdbg("Write %d bytes (32-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint32_t)) - { - DM9X_DATA = *ptr32++; - } -} - -/**************************************************************************** - * Function: dm9x_readsrom - * - * Description: - * Read a word from SROM - * - * Parameters: - * dm9x - Reference to the driver state structure - * offset - SROM offset to read from - * - * Returned Value: - * SROM content at that offset - * - * Assumptions: - * - ****************************************************************************/ - -#if 0 /* Not used */ -static uint16_t dm9x_readsrom(struct dm9x_driver_s *dm9x, int offset) -{ - putreg(DM9X_EEPHYA, offset); - putreg(DM9X_EEPHYC, DM9X_EEPHYC_ERPRR); - up_udelay(200); - putreg(DM9X_EEPHYC, 0x00); - return (getreg(DM9X_EEPHYDL) + (getreg(DM9X_EEPHYDH) << 8) ); -} -#endif - -/**************************************************************************** - * Function: dm9x_phyread and dm9x_phywrite - * - * Description: - * Read/write data from/to the PHY - * - * Parameters: - * dm9x - Reference to the driver state structure - * reg - PHY register offset - * value - The value to write to the PHY register (dm9x_write only) - * - * Returned Value: - * The value read from the PHY (dm9x_read only) - * - * Assumptions: - * - ****************************************************************************/ - -static uint16_t dm9x_phyread(struct dm9x_driver_s *dm9x, int reg) -{ - /* Setup DM9X_EEPHYA, the EEPROM/PHY address register */ - - putreg(DM9X_EEPHYA, DM9X_EEPHYA_EROA | reg); - - /* Issue PHY read command pulse in the EEPROM/PHY control register */ - - putreg(DM9X_EEPHYC, (DM9X_EEPHYC_ERPRR|DM9X_EEPHYC_EPOS)); - up_udelay(100); - putreg(DM9X_EEPHYC, 0x00); - - /* Return the data from the EEPROM/PHY data register pair */ - - return (((uint16_t)getreg(DM9X_EEPHYDH)) << 8) | (uint16_t)getreg(DM9X_EEPHYDL); -} - -static void dm9x_phywrite(struct dm9x_driver_s *dm9x, int reg, uint16_t value) -{ - /* Setup DM9X_EEPHYA, the EEPROM/PHY address register */ - - putreg(DM9X_EEPHYA, DM9X_EEPHYA_EROA | reg); - - /* Put the data to write in the EEPROM/PHY data register pair */ - - putreg(DM9X_EEPHYDL, (value & 0xff)); - putreg(DM9X_EEPHYDH, ((value >> 8) & 0xff)); - - /* Issue PHY write command pulse in the EEPROM/PHY control register */ - - putreg(DM9X_EEPHYC, (DM9X_EEPHYC_ERPRW|DM9X_EEPHYC_EPOS)); - up_udelay(500); - putreg(DM9X_EEPHYC, 0x0); -} - -/**************************************************************************** - * Function: dm9x_resetstatistics - * - * Description: - * Reset all DM90x0 statistics - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DM9X_STATS) -static void dm9x_resetstatistics(struct dm9x_driver_s *dm9x) -{ - dm9x->dm_ntxpackets = 0; /* Count of packets sent */ - dm9x->dm_ntxbytes = 0; /* Count of bytes sent */ - dm9x->dm_ntxerrors = 0; /* Count of TX errors */ - dm9x->dm_nrxpackets = 0; /* Count of packets received */ - dm9x->dm_nrxbytes = 0; /* Count of bytes received */ - dm9x->dm_nrxfifoerrors = 0; /* Count of RX FIFO overflow errors */ - dm9x->dm_nrxcrcerrors = 0; /* Count of RX CRC errors */ - dm9x->dm_nrxlengtherrors = 0; /* Count of RX length errors */ - dm9x->dm_nphyserrors = 0; /* Count of physical layer errors */ - dm9x->dm_nresets = 0; /* Counts number of resets */ - dm9x->dm_ntxtimeouts = 0; /* Counts resets caused by TX timeouts */ -} -#endif - -/**************************************************************************** - * Function: dm9x_dumpstatistics - * - * Description: - * Print the current value of all DM90x0 statistics - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DM9X_STATS) && defined(CONFIG_DEBUG) -static void dm9x_dumpstatistics(struct dm9x_driver_s *dm9x) -{ - ndbg("TX packets: %d\n", dm9x->dm_ntxpackets); - ndbg(" bytes: %d\n", dm9x->dm_ntxbytes); - ndbg(" errors: %d\n", dm9x->dm_ntxerrors); - ndbg("RX packets: %d\n", dm9x->dm_nrxpackets); - ndbg(" bytes: %d\n", dm9x->dm_nrxbytes); - ndbg(" FIFO overflows: %d\n", dm9x->dm_nrxfifoerrors); - ndbg(" CRC errors: %d\n", dm9x->dm_nrxcrcerrors); - ndbg(" length errors: %d\n", dm9x->dm_nrxlengtherrors); - ndbg("Physical layer errors: %d\n", dm9x->dm_nphyserrors); - ndbg("Resets: %d\n", dm9x->dm_nresets); - ndbg("TX timeout resets: %d\n", dm9x->dm_ntxtimeouts); -} -#endif - -/**************************************************************************** - * Function: dm9x_rxchecksumready - * - * Description: - * Return true if the RX checksum is available - * - * Parameters: - * rxbyte - * - * Returned Value: - * true: checksum is ready - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DM9X_CHECKSUM) -static inline bool dm9x_rxchecksumready(uint8_t rxbyte) -{ - if ((rxbyte & 0x01) == 0) - { - return false; - } - - return ((rxbyte >> 4) | 0x01) != 0; -} -#endif - -/**************************************************************************** - * Function: dm9x_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_transmit(struct dm9x_driver_s *dm9x) -{ - /* Check if there is room in the DM90x0 to hold another packet. In 100M mode, - * that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) - { - /* Increment count of packets transmitted */ - - dm9x->dm_ntxpending++; -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_ntxpackets++; - dm9x->dm_ntxbytes += dm9x->dm_dev.d_len; -#endif - - /* Disable all DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRDISABLE); - - /* Set the TX length */ - - putreg(DM9X_TXPLL, (dm9x->dm_dev.d_len & 0xff)); - putreg(DM9X_TXPLH, (dm9x->dm_dev.d_len >> 8) & 0xff); - - /* Move the data to be sent into TX SRAM */ - - DM9X_INDEX = DM9X_MWCMD; - dm9x->dm_write(dm9x->dm_dev.d_buf, dm9x->dm_dev.d_len); - -#if !defined(CONFIG_DM9X_ETRANS) - /* Issue TX polling command */ - - putreg(DM9X_TXC, 0x1); /* Cleared after TX complete*/ -#endif - - /* Clear count of back-to-back RX packet transfers */ - - dm9x->ncrxpackets = 0; - - /* Re-enable DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRENABLE); - - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - - (void)wd_start(dm9x->dm_txtimeout, DM6X_TXTIMEOUT, dm9x_txtimeout, 1, (uint32_t)dm9x); - return OK; - } - return -EBUSY; -} - -/**************************************************************************** - * Function: dm9x_uiptxpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from uip_poll(). uip_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the DM90x0 is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_uiptxpoll(struct uip_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (dm9x->dm_dev.d_len > 0) - { - uip_arp_out(&dm9x->dm_dev); - dm9x_transmit(dm9x); - - /* Check if there is room in the DM90x0 to hold another packet. In 100M mode, - * that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending > 1 || !dm9x->dm_b100M) - { - /* Returning a non-zero value will terminate the poll operation */ - - return 1; - } - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: dm9x_receive - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_receive(struct dm9x_driver_s *dm9x) -{ - union rx_desc_u rx; - bool bchecksumready; - uint8_t mdrah; - uint8_t mdral; - uint8_t rxbyte; - - nvdbg("Packet received\n"); - - do - { - /* Store the value of memory data read address register */ - - mdrah = getreg(DM9X_MDRAH); - mdral = getreg(DM9X_MDRAL); - - getreg(DM9X_MRCMDX); /* Dummy read */ - rxbyte = (uint8_t)DM9X_DATA; /* Get the most up-to-date data */ - - /* Packet ready for receive check */ - - bchecksumready = dm9x_rxchecksumready(rxbyte); - if (!bchecksumready) - { - break; - } - - /* A packet is ready now. Get status/length */ - - DM9X_INDEX = DM9X_MRCMD; /* set read ptr ++ */ - - /* Read packet status & length */ - - dm9x->dm_read((uint8_t*)&rx, 4); - - /* Check if any errors were reported by the hardware */ - - if (rx.desc.rx_status & 0xbf) - { - /* Bad RX packet... update statistics */ - -#if defined(CONFIG_DM9X_STATS) - if (rx.desc.rx_status & 0x01) - { - dm9x->dm_nrxfifoerrors++; - ndbg("RX FIFO error: %d\n", dm9x->dm_nrxfifoerrors); - } - - if (rx.desc.rx_status & 0x02) - { - dm9x->dm_nrxcrcerrors++; - ndbg("RX CRC error: %d\n", dm9x->dm_nrxcrcerrors); - } - - if (rx.desc.rx_status & 0x80) - { - dm9x->dm_nrxlengtherrors++; - ndbg("RX length error: %d\n", dm9x->dm_nrxlengtherrors); - } - - if (rx.desc.rx_status & 0x08) - { - dm9x->dm_nphyserrors++; - ndbg("Physical Layer error: %d\n", dm9x->dm_nphyserrors); - } -#else - ndbg("Received packet with errors: %02x\n", rx.desc.rx_status); -#endif - /* Drop this packet and continue to check the next packet */ - - dm9x->dm_discard(rx.desc.rx_len); - } - - /* Also check if the packet is a valid size for the uIP configuration */ - - else if (rx.desc.rx_len < UIP_LLH_LEN || rx.desc.rx_len > (CONFIG_NET_BUFSIZE + 2)) - { -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_nrxlengtherrors++; - ndbg("RX length error: %d\n", dm9x->dm_nrxlengtherrors); -#endif - /* Drop this packet and continue to check the next packet */ - - dm9x->dm_discard(rx.desc.rx_len); - } - else - { - /* Good packet... Copy the packet data out of SRAM and pass it one to uIP */ - - dm9x->dm_dev.d_len = rx.desc.rx_len; - dm9x->dm_read(dm9x->dm_dev.d_buf, rx.desc.rx_len); - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(UIP_ETHTYPE_IP6)) -#else - if (BUF->type == HTONS(UIP_ETHTYPE_IP)) -#endif - { - uip_arp_ipin(&dm9x->dm_dev); - uip_input(&dm9x->dm_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (dm9x->dm_dev.d_len > 0) - { - uip_arp_out(&dm9x->dm_dev); - dm9x_transmit(dm9x); - } - } - else if (BUF->type == htons(UIP_ETHTYPE_ARP)) - { - uip_arp_arpin(&dm9x->dm_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (dm9x->dm_dev.d_len > 0) - { - dm9x_transmit(dm9x); - } - } - } - -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_nrxpackets++; - dm9x->dm_nrxbytes += rx.desc.rx_len; -#endif - dm9x->ncrxpackets++; - } - while ((rxbyte & 0x01) == DM9X_PKTRDY && dm9x->ncrxpackets < DM9X_CRXTHRES); - nvdbg("All RX packets processed\n"); -} - -/**************************************************************************** - * Function: dm9x_txdone - * - * Description: - * An interrupt was received indicating that the last TX packet(s) is done - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_txdone(struct dm9x_driver_s *dm9x) -{ - int nsr; - - nvdbg("TX done\n"); - - /* Another packet has completed transmission. Decrement the count of - * of pending TX transmissions. - */ - - nsr = getreg(DM9X_NETS); - if (nsr & DM9X_NETS_TX1END) - { - if (dm9x->dm_ntxpending) - { - dm9x->dm_ntxpending--; - } - else - { - ndbg("Bad TX count (TX1END)\n"); - } - } - - if (nsr & DM9X_NETS_TX2END) - { - if (dm9x->dm_ntxpending) - { - dm9x->dm_ntxpending--; - } - else - { - ndbg("Bad TX count (TX2END)\n"); - } - } - - /* Cancel the TX timeout */ - - if (dm9x->dm_ntxpending == 0) - { - wd_cancel(dm9x->dm_txtimeout); - } - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&dm9x->dm_dev, dm9x_uiptxpoll); -} - -/**************************************************************************** - * Function: dm9x_interrupt - * - * Description: - * DM90x0 interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_interrupt(int irq, FAR void *context) -{ -#if CONFIG_DM9X_NINTERFACES == 1 - register struct dm9x_driver_s *dm9x = &g_dm9x[0]; -#else -# error "Additional logic needed to support multiple interfaces" -#endif - uint8_t isr; - uint8_t save; - int i; - - /* Save previous register address */ - - save = (uint8_t)DM9X_INDEX; - - /* Disable all DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRDISABLE); - - /* Get and clear the DM90x0 interrupt status bits */ - - isr = getreg(DM9X_ISR); - putreg(DM9X_ISR, isr); - nvdbg("Interrupt status: %02x\n", isr); - - /* Check for link status change */ - - if (isr & DM9X_INT_LNKCHG) - { - /* Wait up to 0.5s for link OK */ - - for (i = 0; i < 500; i++) - { - dm9x_phyread(dm9x,0x1); - if (dm9x_phyread(dm9x,0x1) & 0x4) /*Link OK*/ - { - /* Wait to get detected speed */ - - for (i = 0; i < 200; i++) - { - up_mdelay(1); - } - - /* Set the new network speed */ - - if (dm9x_phyread(dm9x, 0) & 0x2000) - { - dm9x->dm_b100M = true; - } - else - { - dm9x->dm_b100M = false; - } - break; - } - up_mdelay(1); - } - ndbg("delay: %dmS speed: %s\n", i, dm9x->dm_b100M ? "100M" : "10M"); - } - - /* Check if we received an incoming packet */ - - if (isr & DM9X_INT_PR) - { - dm9x_receive(dm9x); - } - - /* Check if we are able to transmit a packet */ - - if (isr & DM9X_INT_PT) - { - dm9x_txdone(dm9x); - } - - /* If the number of consecutive receive packets exceeds a threshold, - * then disable the RX interrupt. - */ - - if (dm9x->ncrxpackets >= DM9X_CRXTHRES) - { - /* Eanble all DM90x0 interrupts EXCEPT for RX */ - - putreg(DM9X_IMR, DM9X_IMRRXDISABLE); - } - else - { - /* Enable all DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRENABLE); - } - - /* Restore previous register address */ - - DM9X_INDEX = save; - return OK; -} - -/**************************************************************************** - * Function: dm9x_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the DM90x0 and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_txtimeout(int argc, uint32_t arg, ...) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)arg; - - ndbg("TX timeout\n"); - - /* Increment statistics and dump debug info */ - -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_ntxtimeouts++; - dm9x->dm_ntxerrors++; -#endif - - ndbg(" TX packet count: %d\n", dm9x->dm_ntxpending); -#if defined(CONFIG_DM9X_STATS) - ndbg(" TX timeouts: %d\n", dm9x->dm_ntxtimeouts); -#endif - ndbg(" TX read pointer address: 0x%02x:%02x\n", - getreg(DM9X_TRPAH), getreg(DM9X_TRPAL)); - ndbg(" Memory data write address: 0x%02x:%02x (DM9010)\n", - getreg(DM9X_MDWAH), getreg(DM9X_MDWAL)); - - /* Then reset the DM90x0 */ - - dm9x_reset(dm9x); - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&dm9x->dm_dev, dm9x_uiptxpoll); -} - -/**************************************************************************** - * Function: dm9x_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_polltimer(int argc, uint32_t arg, ...) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)arg; - - /* If the number of contiguous RX packets exceeds a threshold, reset the counter and - * re-enable RX interrupts - */ - - if (dm9x->ncrxpackets >= DM9X_CRXTHRES) - { - dm9x->ncrxpackets = 0; - putreg(DM9X_IMR, DM9X_IMRENABLE); - } - - /* Check if there is room in the DM90x0 to hold another packet. In 100M mode, - * that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) - { - /* If so, update TCP timing states and poll uIP for new XMIT data */ - - (void)uip_timer(&dm9x->dm_dev, dm9x_uiptxpoll, DM6X_POLLHSEC); - } - - /* Setup the watchdog poll timer again */ - - (void)wd_start(dm9x->dm_txpoll, DM6X_WDDELAY, dm9x_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: dm9x_phymode - * - * Description: - * Configure the PHY operating mode - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static inline void dm9x_phymode(struct dm9x_driver_s *dm9x) -{ - uint16_t phyreg0; - uint16_t phyreg4; - -#if CONFIG_DM9X_MODE == DM9X_MODE_AUTO - phyreg0 = 0x1200; /* Auto-negotiation & Restart Auto-negotiation */ - phyreg4 = 0x01e1; /* Default flow control disable*/ -#elif CONFIG_DM9X_MODE == DM9X_MODE_10MHD - phyreg4 = 0x21; - phyreg0 = 0x1000; -#elif CONFIG_DM9X_MODE == DM9X_MODE_10MFD - phyreg4 = 0x41; - phyreg0 = 0x1100; -#elif CONFIG_DM9X_MODE == DM9X_MODE_100MHD - phyreg4 = 0x81; - phyreg0 = 0x3000; -#elif CONFIG_DM9X_MODE == DM9X_MODE_100MFD - phyreg4 = 0x101; - phyreg0 = 0x3100; -#else -# error "Recognized PHY mode" -#endif - - dm9x_phywrite(dm9x, 0, phyreg0); - dm9x_phywrite(dm9x, 4, phyreg4); -} - -/**************************************************************************** - * Function: dm9x_ifup - * - * Description: - * NuttX Callback: Bring up the DM90x0 interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_ifup(struct uip_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - uint8_t netstatus; - int i; - - ndbg("Bringing up: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Initilize DM90x0 chip */ - - dm9x_bringup(dm9x); - - /* Check link state and media speed (waiting up to 3s for link OK) */ - - dm9x->dm_b100M = false; - for (i = 0; i < 3000; i++) - { - netstatus = getreg(DM9X_NETS); - if (netstatus & DM9X_NETS_LINKST) - { - /* Link OK... Wait a bit before getting the detected speed */ - - up_mdelay(200); - netstatus = getreg(DM9X_NETS); - if ((netstatus & DM9X_NETS_SPEED) == 0) - { - dm9x->dm_b100M = true; - } - break; - } - i++; - up_mdelay(1); - } - - ndbg("delay: %dmS speed: %s\n", i, dm9x->dm_b100M ? "100M" : "10M"); - - /* Set and activate a timer process */ - - (void)wd_start(dm9x->dm_txpoll, DM6X_WDDELAY, dm9x_polltimer, 1, (uint32_t)dm9x); - - /* Enable the DM9X interrupt */ - - dm9x->dm_bifup = true; - up_enable_irq(CONFIG_DM9X_IRQ); - return OK; -} - -/**************************************************************************** - * Function: dm9x_ifdown - * - * Description: - * NuttX Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_ifdown(struct uip_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - irqstate_t flags; - - ndbg("Stopping\n"); - - /* Disable the DM9X interrupt */ - - flags = irqsave(); - up_disable_irq(CONFIG_DM9X_IRQ); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(dm9x->dm_txpoll); - wd_cancel(dm9x->dm_txtimeout); - - /* Reset the device */ - - dm9x_phywrite(dm9x, 0x00, 0x8000); /* PHY reset */ - putreg(DM9X_GPD, 0x01); /* Power-down PHY (GEPIO0=1) */ - putreg(DM9X_IMR, DM9X_IMRDISABLE); /* Disable all interrupts */ - putreg(DM9X_RXC, 0x00); /* Disable RX */ - putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */ - - dm9x->dm_bifup = false; - irqrestore(flags); - - /* Dump statistics */ - - dm9x_dumpstatistics(dm9x); - return OK; -} - -/**************************************************************************** - * Function: dm9x_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int dm9x_txavail(struct uip_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - irqstate_t flags; - - ndbg("Polling\n"); - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (dm9x->dm_bifup) - { - - /* Check if there is room in the DM90x0 to hold another packet. In 100M - * mode, that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) - { - /* If so, then poll uIP for new XMIT data */ - - (void)uip_poll(&dm9x->dm_dev, dm9x_uiptxpoll); - } - } - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: dm9x_addmac - * - * Description: - * NuttX Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int dm9x_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - return OK; -} -#endif - -/**************************************************************************** - * Function: dm9x_rmmac - * - * Description: - * NuttX Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int dm9x_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - return OK; -} -#endif - -/**************************************************************************** - * Function: dm9x_bringup - * - * Description: - * Initialize the dm90x0 chip - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_bringup(struct dm9x_driver_s *dm9x) -{ - ndbg("Initializing\n"); - - /* Set the internal PHY power-on, GPIOs normal, and wait 2ms */ - - putreg(DM9X_GPD, 0x01); /* Power-down the PHY (GEPIO0=1) */ - up_udelay(500); - putreg(DM9X_GPD, 0x00); /* Preactivate PHY (GPIO0=0 */ - up_udelay(20); /* Wait 20us for PHY power-on ready */ - - /* Do a software reset and wait 20us (twice). The reset autoclears - * in 10us; 20us guarantees completion of the reset - */ - - putreg(DM9X_NETC, (DM9X_NETC_RST|DM9X_NETC_LBK1)); - up_udelay(20); - putreg(DM9X_NETC, (DM9X_NETC_RST|DM9X_NETC_LBK1)); - up_udelay(20); - - /* Configure I/O mode */ - - switch (getreg(DM9X_ISR) & DM9X_ISR_IOMODEM) - { - case DM9X_ISR_IOMODE8: - dm9x->dm_read = read8; - dm9x->dm_write = write8; - dm9x->dm_discard = discard8; - break; - - case DM9X_ISR_IOMODE16: - dm9x->dm_read = read16; - dm9x->dm_write = write16; - dm9x->dm_discard = discard16; - break; - - case DM9X_ISR_IOMODE32: - dm9x->dm_read = read32; - dm9x->dm_write = write32; - dm9x->dm_discard = discard32; - break; - - default: - break; - } - - /* Program PHY operating mode */ - - dm9x_phymode(dm9x); - - /* Program operating mode */ - - putreg(DM9X_NETC, 0x00); /* Network control */ - putreg(DM9X_TXC, 0x00); /* Clear TX Polling */ - putreg(DM9X_BPTHRES, 0x3f); /* Less 3kb, 600us */ - putreg(DM9X_SMODEC, 0x00); /* Special mode */ - putreg(DM9X_NETS, (DM9X_NETS_WAKEST|DM9X_NETS_TX1END|DM9X_NETS_TX2END)); /* Clear TX status */ - putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */ - -#if defined(CONFIG_DM9X_CHECKSUM) - putreg(DM9X_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */ - putreg(DM9X_RCSR, 0x02); /* Receive checksum enable */ -#endif - -#if defined(CONFIG_DM9X_ETRANS) - putreg(DM9X_ETXCSR, 0x83); -#endif - - /* Initialize statistics */ - - dm9x->ncrxpackets = 0; /* Number of continuous RX packets */ - dm9x->dm_ntxpending = 0; /* Number of pending TX packets */ - dm9x_resetstatistics(dm9x); - - /* Activate DM9000A/DM9010 */ - - putreg(DM9X_RXC, DM9X_RXCSETUP | 1); /* RX enable */ - putreg(DM9X_IMR, DM9X_IMRENABLE); /* Enable TX/RX interrupts */ -} - -/**************************************************************************** - * Function: dm9x_reset - * - * Description: - * Stop, reset, re-initialize, and restart the DM90x0 chip and driver. At - * present, the chip is only reset after a TX timeout. - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_reset(struct dm9x_driver_s *dm9x) -{ - uint8_t save; - int i; - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(dm9x->dm_txpoll); - wd_cancel(dm9x->dm_txtimeout); - - /* Save previous register address */ - - save = (uint8_t)DM9X_INDEX; - -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_nresets++; -#endif - dm9x_bringup(dm9x); - - /* Wait up to 1 second for the link to be OK */ - - dm9x->dm_b100M = false; - for (i = 0; i < 1000; i++) - { - if (dm9x_phyread(dm9x,0x1) & 0x4) - { - if (dm9x_phyread(dm9x, 0) &0x2000) - { - dm9x->dm_b100M = true; - } - break; - } - up_mdelay(1); - } - - /* Restore previous register address */ - - DM9X_INDEX = save; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: dm9x_initialize - * - * Description: - * Initialize the DM90x0 driver - * - * Parameters: - * None - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -/* Initialize the DM90x0 chip and driver */ - -int dm9x_initialize(void) -{ - uint8_t *mptr; - uint16_t vid; - uint16_t pid; - int i; - int j; - - /* Get the chip vendor ID and product ID */ - - vid = (((uint16_t)getreg(DM9X_VIDH)) << 8) | (uint16_t)getreg(DM9X_VIDL); - pid = (((uint16_t)getreg(DM9X_PIDH)) << 8) | (uint16_t)getreg(DM9X_PIDL); - nlldbg("I/O base: %08x VID: %04x PID: %04x\n", CONFIG_DM9X_BASE, vid, pid); - - /* Check if a DM90x0 chip is recognized at this I/O base */ - - if (vid != DM9X_DAVICOMVID || (pid != DM9X_DM9000PID && pid != DM9X_DM9010PID)) - { - nlldbg("DM90x0 vendor/product ID not found at this base address\n"); - return -ENODEV; - } - - /* Attach the IRQ to the driver */ - - if (irq_attach(CONFIG_DM9X_IRQ, dm9x_interrupt)) - { - /* We could not attach the ISR to the ISR */ - - nlldbg("irq_attach() failed\n"); - return -EAGAIN; - } - - /* Initialize the driver structure */ - - memset(g_dm9x, 0, CONFIG_DM9X_NINTERFACES*sizeof(struct dm9x_driver_s)); - g_dm9x[0].dm_dev.d_ifup = dm9x_ifup; /* I/F down callback */ - g_dm9x[0].dm_dev.d_ifdown = dm9x_ifdown; /* I/F up (new IP address) callback */ - g_dm9x[0].dm_dev.d_txavail = dm9x_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - g_dm9x[0].dm_dev.d_addmac = dm9x_addmac; /* Add multicast MAC address */ - g_dm9x[0].dm_dev.d_rmmac = dm9x_rmmac; /* Remove multicast MAC address */ -#endif - g_dm9x[0].dm_dev.d_private = (void*)g_dm9x; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - g_dm9x[0].dm_txpoll = wd_create(); /* Create periodic poll timer */ - g_dm9x[0].dm_txtimeout = wd_create(); /* Create TX timeout timer */ - - /* Read the MAC address */ - - mptr = g_dm9x[0].dm_dev.d_mac.ether_addr_octet; - for (i = 0, j = DM9X_PAB0; i < ETHER_ADDR_LEN; i++, j++) - { - mptr[i] = getreg(j); - } - - nlldbg("MAC: %0x:%0x:%0x:%0x:%0x:%0x\n", - mptr[0], mptr[1], mptr[2], mptr[3], mptr[4], mptr[5]); - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - (void)netdev_register(&g_dm9x[0].dm_dev); - return OK; -} - -#endif /* CONFIG_NET && CONFIG_NET_DM90x0 */ - diff --git a/nuttx/drivers/net/e1000.c b/nuttx/drivers/net/e1000.c deleted file mode 100644 index cae6f39b4..000000000 --- a/nuttx/drivers/net/e1000.c +++ /dev/null @@ -1,1042 +0,0 @@ -/**************************************************************************** - * drivers/net/e1000.c - * - * Copyright (C) 2011 Yu Qiang. All rights reserved. - * Author: Yu Qiang - * - * This file is a part of NuttX: - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "e1000.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define E1000_WDDELAY (1*CLK_TCK) -#define E1000_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define E1000_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct uip_eth_hdr *)e1000->uip_dev.d_buf) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct tx_ring { - struct tx_desc *desc; - char *buf; - int tail; // where to write desc -}; - -struct rx_ring { - struct rx_desc *desc; - char *buf; - int head; // where to read - int tail; // where to release free desc - int free; // number of freed desc -}; - -struct e1000_dev { - uint32_t phy_mem_base; - uint32_t io_mem_base; - uint32_t mem_size; - int pci_dev_id; - uint16_t pci_addr; - unsigned char src_mac[6]; - unsigned char dst_mac[6]; - struct irq_action int_desc; - struct tx_ring tx_ring; - struct rx_ring rx_ring; - struct e1000_dev *next; - - // NuttX net data - bool bifup; /* true:ifup false:ifdown */ - WDOG_ID txpoll; /* TX poll timer */ - WDOG_ID txtimeout; /* TX timeout timer */ - - /* This holds the information visible to uIP/NuttX */ - - struct uip_driver_s uip_dev; /* Interface understood by uIP */ -}; - -struct e1000_dev_head { - struct e1000_dev *next; -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct e1000_dev_head e1000_list = {0}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Common TX logic */ - -static int e1000_transmit(struct e1000_dev *e1000); -static int e1000_uiptxpoll(struct uip_driver_s *dev); - -/* Interrupt handling */ - -static void e1000_receive(struct e1000_dev *e1000); - -/* Watchdog timer expirations */ - -static void e1000_polltimer(int argc, uint32_t arg, ...); -static void e1000_txtimeout(int argc, uint32_t arg, ...); - -/* NuttX callback functions */ - -static int e1000_ifup(struct uip_driver_s *dev); -static int e1000_ifdown(struct uip_driver_s *dev); -static int e1000_txavail(struct uip_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int e1000_addmac(struct uip_driver_s *dev, const uint8_t *mac); -static int e1000_rmmac(struct uip_driver_s *dev, const uint8_t *mac); -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -static inline void e1000_outl(struct e1000_dev *dev, int reg, uint32_t val) -{ - writel(dev->io_mem_base+reg, val); -} - -static inline uint32_t e1000_inl(struct e1000_dev *dev, int reg) -{ - return readl(dev->io_mem_base+reg); -} - -/****************************** e1000 driver ********************************/ - -void e1000_reset(struct e1000_dev *dev) -{ - uint32_t dev_control; - - // Reset the network controller hardware - dev_control = 0; - dev_control |= (1<<0); // FD-bit (Full Duplex) - dev_control |= (0<<2); // GIOMD-bit (GIO Master Disable) - dev_control |= (1<<3); // LRST-bit (Link Reset) - dev_control |= (1<<6); // SLU-bit (Set Link Up) - dev_control |= (2<<8); // SPEED=2 (1000Mbps) - dev_control |= (0<<11); // FRCSPD-bit (Force Speed) - dev_control |= (0<<12); // FRCDPLX-bit (Force Duplex) - dev_control |= (0<<20); // ADVD3WUC-bit (Advertise D3 Wake Up Cap) - dev_control |= (1<<26); // RST-bit (Device Reset) - dev_control |= (1<<27); // RFCE-bit (Receive Flow Control Enable) - dev_control |= (1<<28); // TFCE-bit (Transmit Flow Control Enable) - dev_control |= (0<<30); // VME-bit (VLAN Mode Enable) - dev_control |= (0<<31); // PHY_RST-bit (PHY Reset) - - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); - e1000_outl(dev, E1000_STATUS, 0x00000000); - e1000_outl(dev, E1000_CTRL, dev_control); - dev_control &= ~(1<<26); // clear RST-bit (Device Reset) - e1000_outl(dev, E1000_CTRL, dev_control); - up_mdelay(10); - e1000_outl(dev, E1000_CTRL_EXT, 0x001401C0); - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); -} - -void e1000_turn_on(struct e1000_dev *dev) -{ - int tx_control, rx_control; - uint32_t ims = 0; - - // turn on the controller's receive engine - rx_control = e1000_inl(dev, E1000_RCTL); - rx_control |= (1<<1); - e1000_outl(dev, E1000_RCTL, rx_control); - - // turn on the controller's transmit engine - tx_control = e1000_inl(dev, E1000_TCTL); - tx_control |= (1<<1); - e1000_outl(dev, E1000_TCTL, tx_control); - - // enable the controller's interrupts - e1000_outl(dev, E1000_ICR, 0xFFFFFFFF); - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); - - ims |= 1<<0; // TXDW - ims |= 1<<1; // TXQE - ims |= 1<<2; // LSC - ims |= 1<<4; // RXDMT0 - ims |= 1<<7; // RXT0 - e1000_outl(dev, E1000_IMS, ims); -} - -void e1000_turn_off(struct e1000_dev *dev) -{ - int tx_control, rx_control; - - // turn off the controller's receive engine - rx_control = e1000_inl(dev, E1000_RCTL); - rx_control &= ~(1<<1); - e1000_outl(dev, E1000_RCTL, rx_control); - - // turn off the controller's transmit engine - tx_control = e1000_inl(dev, E1000_TCTL); - tx_control &= ~(1<<1); - e1000_outl(dev, E1000_TCTL, tx_control); - - // turn off the controller's interrupts - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); -} - -void e1000_init(struct e1000_dev *dev) -{ - uint32_t rxd_phys, txd_phys, kmem_phys; - uint32_t rx_control, tx_control; - uint32_t pba; - int i; - - e1000_reset(dev); - - // configure the controller's 'receive' engine - rx_control = 0; - rx_control |= (0<<1); // EN-bit (Enable) - rx_control |= (0<<2); // SPB-bit (Store Bad Packets) - rx_control |= (0<<3); // UPE-bit (Unicast Promiscuous Mode) - rx_control |= (1<<4); // MPE-bit (Multicast Promiscuous Mode) - rx_control |= (0<<5); // LPE-bit (Long Packet Enable) - rx_control |= (0<<6); // LBM=0 (Loop-Back Mode) - rx_control |= (0<<8); // RDMTS=0 (Rx Descriptor Min Threshold Size) - rx_control |= (0<<10); // DTYPE=0 (Descriptor Type) - rx_control |= (0<<12); // MO=0 (Multicast Offset) - rx_control |= (1<<15); // BAM-bit (Broadcast Address Mode) - rx_control |= (0<<16); // BSIZE=0 (Buffer Size = 2048) - rx_control |= (0<<18); // VLE-bit (VLAN filter Enable) - rx_control |= (0<<19); // CFIEN-bit (Canonical Form Indicator Enable) - rx_control |= (0<<20); // CFI-bit (Canonical Form Indicator) - rx_control |= (1<<22); // DPF-bit (Discard Pause Frames) - rx_control |= (0<<23); // PMCF-bit (Pass MAC Control Frames) - rx_control |= (0<<25); // BSEX=0 (Buffer Size EXtension) - rx_control |= (1<<26); // SECRC-bit (Strip Ethernet CRC) - rx_control |= (0<<27); // FLEXBUF=0 (Flexible Buffer size) - e1000_outl(dev, E1000_RCTL, rx_control); - - // configure the controller's 'transmit' engine - tx_control = 0; - tx_control |= (0<<1); // EN-bit (Enable) - tx_control |= (1<<3); // PSP-bit (Pad Short Packets) - tx_control |= (15<<4); // CT=15 (Collision Threshold) - tx_control |= (63<<12); // COLD=63 (Collision Distance) - tx_control |= (0<<22); // SWXOFF-bit (Software XOFF) - tx_control |= (1<<24); // RTLC-bit (Re-Transmit on Late Collision) - tx_control |= (0<<25); // UNORTX-bit (Underrun No Re-Transmit) - tx_control |= (0<<26); // TXCSCMT=0 (TxDesc Mininum Threshold) - tx_control |= (0<<28); // MULR-bit (Multiple Request Support) - e1000_outl(dev, E1000_TCTL, tx_control); - - // hardware flow control - pba = e1000_inl(dev, E1000_PBA); - // get receive FIFO size - pba = (pba & 0x000000ff)<<10; - e1000_outl(dev, E1000_FCAL, 0x00C28001); - e1000_outl(dev, E1000_FCAH, 0x00000100); - e1000_outl(dev, E1000_FCT, 0x00008808); - e1000_outl(dev, E1000_FCTTV, 0x00000680); - e1000_outl(dev, E1000_FCRTL, (pba*8/10)|0x80000000); - e1000_outl(dev, E1000_FCRTH, pba*9/10); - - // setup tx rings - txd_phys = PADDR((uintptr_t)dev->tx_ring.desc); - kmem_phys = PADDR((uintptr_t)dev->tx_ring.buf); - for (i=0; itx_ring.desc[i].base_address = kmem_phys; - dev->tx_ring.desc[i].packet_length = 0; - dev->tx_ring.desc[i].cksum_offset = 0; - dev->tx_ring.desc[i].cksum_origin = 0; - dev->tx_ring.desc[i].desc_status = 1; - dev->tx_ring.desc[i].desc_command = (1<<0)|(1<<1)|(1<<3); - dev->tx_ring.desc[i].special_info = 0; - } - dev->tx_ring.tail = 0; - e1000_outl(dev, E1000_TDT, 0); - e1000_outl(dev, E1000_TDH, 0); - // tell controller the location, size, and fetch-policy for Tx queue - e1000_outl(dev, E1000_TDBAL, txd_phys); - e1000_outl(dev, E1000_TDBAH, 0x00000000); - e1000_outl(dev, E1000_TDLEN, CONFIG_E1000_N_TX_DESC*16); - e1000_outl(dev, E1000_TXDCTL, 0x01010000); - - // setup rx rings - rxd_phys = PADDR((uintptr_t)dev->rx_ring.desc); - kmem_phys = PADDR((uintptr_t)dev->rx_ring.buf); - for (i=0; irx_ring.desc[i].base_address = kmem_phys; - dev->rx_ring.desc[i].packet_length = 0; - dev->rx_ring.desc[i].packet_cksum = 0; - dev->rx_ring.desc[i].desc_status = 0; - dev->rx_ring.desc[i].desc_errors = 0; - dev->rx_ring.desc[i].vlan_tag = 0; - } - dev->rx_ring.head = 0; - dev->rx_ring.tail = CONFIG_E1000_N_RX_DESC-1; - dev->rx_ring.free = 0; - // give the controller ownership of all receive descriptors - e1000_outl(dev, E1000_RDH, 0); - e1000_outl(dev, E1000_RDT, CONFIG_E1000_N_RX_DESC-1); - // tell controller the location, size, and fetch-policy for RX queue - e1000_outl(dev, E1000_RDBAL, rxd_phys); - e1000_outl(dev, E1000_RDBAH, 0x00000000); - e1000_outl(dev, E1000_RDLEN, CONFIG_E1000_N_RX_DESC*16); - e1000_outl(dev, E1000_RXDCTL, 0x01010000); - - e1000_turn_on(dev); -} - -/**************************************************************************** - * Function: e1000_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * e1000 - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int e1000_transmit(struct e1000_dev *e1000) -{ - int tail = e1000->tx_ring.tail; - unsigned char *cp = (unsigned char *) - (e1000->tx_ring.buf + tail * CONFIG_E1000_BUFF_SIZE); - int count = e1000->uip_dev.d_len; - - /* Verify that the hardware is ready to send another packet. If we get - * here, then we are committed to sending a packet; Higher level logic - * must have assured that there is not transmission in progress. - */ - - if (!e1000->tx_ring.desc[tail].desc_status) - return -1; - - /* Increment statistics */ - - /* Send the packet: address=skel->sk_dev.d_buf, length=skel->sk_dev.d_len */ - memcpy(cp, e1000->uip_dev.d_buf, e1000->uip_dev.d_len); - - // prepare the transmit-descriptor - e1000->tx_ring.desc[tail].packet_length = count<60 ? 60:count; - e1000->tx_ring.desc[tail].desc_status = 0; - - // give ownership of this descriptor to the network controller - tail = (tail + 1) % CONFIG_E1000_N_TX_DESC; - e1000->tx_ring.tail = tail; - e1000_outl(e1000, E1000_TDT, tail); - - /* Enable Tx interrupts */ - - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - - wd_start(e1000->txtimeout, E1000_TXTIMEOUT, e1000_txtimeout, 1, (uint32_t)e1000); - return OK; -} - -/**************************************************************************** - * Function: e1000_uiptxpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from uip_poll(). uip_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int e1000_uiptxpoll(struct uip_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - int tail = e1000->tx_ring.tail; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (e1000->uip_dev.d_len > 0) { - uip_arp_out(&e1000->uip_dev); - e1000_transmit(e1000); - - /* Check if there is room in the device to hold another packet. If not, - * return a non-zero value to terminate the poll. - */ - if (!e1000->tx_ring.desc[tail].desc_status) - return -1; - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: e1000_receive - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * e1000 - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by interrupt handling logic. - * - ****************************************************************************/ - -static void e1000_receive(struct e1000_dev *e1000) -{ - int head = e1000->rx_ring.head; - unsigned char *cp = (unsigned char *) - (e1000->rx_ring.buf + head * CONFIG_E1000_BUFF_SIZE); - int cnt; - - while (e1000->rx_ring.desc[head].desc_status) { - - /* Check for errors and update statistics */ - - // Here we do not handle packets that exceed packet-buffer size - if ((e1000->rx_ring.desc[head].desc_status & 3) == 1) { - cprintf("NIC READ: Oversized packet\n"); - goto next; - } - - /* Check if the packet is a valid size for the uIP buffer configuration */ - - // get the number of actual data-bytes in this packet - cnt = e1000->rx_ring.desc[head].packet_length; - - if (cnt > CONFIG_NET_BUFSIZE || cnt < 14) { - cprintf("NIC READ: invalid package size\n"); - goto next; - } - - /* Copy the data data from the hardware to e1000->uip_dev.d_buf. Set - * amount of data in e1000->uip_dev.d_len - */ - - // now we try to copy these data-bytes to the UIP buffer - memcpy(e1000->uip_dev.d_buf, cp, cnt); - e1000->uip_dev.d_len = cnt; - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(UIP_ETHTYPE_IP6)) -#else - if (BUF->type == HTONS(UIP_ETHTYPE_IP)) -#endif - { - uip_arp_ipin(&e1000->uip_dev); - uip_input(&e1000->uip_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (e1000->uip_dev.d_len > 0) { - uip_arp_out(&e1000->uip_dev); - e1000_transmit(e1000); - } - } - else if (BUF->type == htons(UIP_ETHTYPE_ARP)) { - uip_arp_arpin(&e1000->uip_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (e1000->uip_dev.d_len > 0) { - e1000_transmit(e1000); - } - } - - next: - e1000->rx_ring.desc[head].desc_status = 0; - e1000->rx_ring.head = (head + 1) % CONFIG_E1000_N_RX_DESC; - e1000->rx_ring.free++; - head = e1000->rx_ring.head; - cp = (unsigned char *)(e1000->rx_ring.buf + head * CONFIG_E1000_BUFF_SIZE); - } -} - -/**************************************************************************** - * Function: e1000_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void e1000_txtimeout(int argc, uint32_t arg, ...) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)arg; - - /* Increment statistics and dump debug info */ - - /* Then reset the hardware */ - e1000_init(e1000); - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&e1000->uip_dev, e1000_uiptxpoll); -} - -/**************************************************************************** - * Function: e1000_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void e1000_polltimer(int argc, uint32_t arg, ...) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)arg; - int tail = e1000->tx_ring.tail; - - /* Check if there is room in the send another TX packet. We cannot perform - * the TX poll if he are unable to accept another packet for transmission. - */ - if (!e1000->tx_ring.desc[tail].desc_status) - return; - - /* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm.. - * might be bug here. Does this mean if there is a transmit in progress, - * we will missing TCP time state updates? - */ - - (void)uip_timer(&e1000->uip_dev, e1000_uiptxpoll, E1000_POLLHSEC); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(e1000->txpoll, E1000_WDDELAY, e1000_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: e1000_ifup - * - * Description: - * NuttX Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int e1000_ifup(struct uip_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - - ndbg("Bringing up: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */ - e1000_init(e1000); - - /* Set and activate a timer process */ - - (void)wd_start(e1000->txpoll, E1000_WDDELAY, e1000_polltimer, 1, (uint32_t)e1000); - - if (e1000_inl(e1000, E1000_STATUS) & 2) - e1000->bifup = true; - else - e1000->bifup = false; - - return OK; -} - -/**************************************************************************** - * Function: e1000_ifdown - * - * Description: - * NuttX Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int e1000_ifdown(struct uip_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - irqstate_t flags; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - - e1000_turn_off(e1000); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(e1000->txpoll); - wd_cancel(e1000->txtimeout); - - /* Put the the EMAC is its reset, non-operational state. This should be - * a known configuration that will guarantee the skel_ifup() always - * successfully brings the interface back up. - */ - //e1000_reset(e1000); - - /* Mark the device "down" */ - - e1000->bifup = false; - irqrestore(flags); - - return OK; -} - -/**************************************************************************** - * Function: e1000_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int e1000_txavail(struct uip_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - int tail = e1000->tx_ring.tail; - irqstate_t flags; - - /* Disable interrupts because this function may be called from interrupt - * level processing. - */ - - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (e1000->bifup) { - /* Check if there is room in the hardware to hold another outgoing packet. */ - if (e1000->tx_ring.desc[tail].desc_status) - (void)uip_poll(&e1000->uip_dev, e1000_uiptxpoll); - } - - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: e1000_addmac - * - * Description: - * NuttX Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int e1000_addmac(struct uip_driver_s *dev, const uint8_t *mac) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Function: e1000_rmmac - * - * Description: - * NuttX Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int e1000_rmmac(struct uip_driver_s *dev, const uint8_t *mac) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -static irqreturn_t e1000_interrupt_handler(int irq, void *dev_id) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev_id; - - /* Get and clear interrupt status bits */ - int intr_cause = e1000_inl(e1000, E1000_ICR); - e1000_outl(e1000, E1000_ICR, intr_cause); - - // not for me - if (intr_cause == 0) - return IRQ_NONE; - - /* Handle interrupts according to status bit settings */ - - // Link status change - if (intr_cause & (1<<2)) { - if (e1000_inl(e1000, E1000_STATUS) & 2) - e1000->bifup = true; - else - e1000->bifup = false; - } - - /* Check if we received an incoming packet, if so, call skel_receive() */ - - // Rx-descriptor Timer expired - if (intr_cause & (1<<7)) - e1000_receive(e1000); - - // Tx queue empty - if (intr_cause & (1<<1)) - wd_cancel(e1000->txtimeout); - - /* Check is a packet transmission just completed. If so, call skel_txdone. - * This may disable further Tx interrupts if there are no pending - * tansmissions. - */ - - // Tx-descriptor Written back - if (intr_cause & (1<<0)) - uip_poll(&e1000->uip_dev, e1000_uiptxpoll); - - - // Rx-Descriptors Low - if (intr_cause & (1<<4)) { - int tail; - tail = e1000->rx_ring.tail + e1000->rx_ring.free; - tail %= CONFIG_E1000_N_RX_DESC; - e1000->rx_ring.tail = tail; - e1000->rx_ring.free = 0; - e1000_outl(e1000, E1000_RDT, tail); - } - - return IRQ_HANDLED; -} - -/******************************* PCI driver *********************************/ - -static pci_id_t e1000_id_table[] = { - {.sep = {INTEL_VENDERID, E1000_82573L}}, - {.sep = {INTEL_VENDERID, E1000_82540EM}}, - {.sep = {INTEL_VENDERID, E1000_82574L}}, - {.sep = {INTEL_VENDERID, E1000_82567LM}}, - {.sep = {INTEL_VENDERID, E1000_82541PI}}, - {.sep = {0,0}} -}; - -static int e1000_probe(uint16_t addr, pci_id_t id) -{ - uint32_t mmio_base, mmio_size; - uint32_t size; - int err; - void *kmem, *omem; - struct e1000_dev *dev; - - // alloc e1000_dev memory - if ((dev = kzalloc(sizeof(struct e1000_dev))) == NULL) - return -1; - - // save pci addr - dev->pci_addr = addr; - - // enable device - if ((err = pci_enable_device(addr, PCI_BUS_MASTER)) < 0) - goto error; - - // get e1000 device type - dev->pci_dev_id = id.join; - - // remap the controller's i/o-memory into kernel's address-space - mmio_base = pci_resource_start(addr, 0); - mmio_size = pci_resource_len(addr, 0); - err = rgmp_memmap_nocache(mmio_base, mmio_size, mmio_base); - if (err) - goto error; - dev->phy_mem_base = mmio_base; - dev->io_mem_base = mmio_base; - dev->mem_size = mmio_size; - - // MAC address - memset(dev->dst_mac, 0xFF, 6); - memcpy(dev->src_mac, (void *)(dev->io_mem_base+E1000_RA), 6); - - // IRQ setup - dev->int_desc.handler = e1000_interrupt_handler; - dev->int_desc.dev_id = dev; - if ((err = pci_request_irq(addr, &dev->int_desc, 0)) < 0) - goto err0; - - // Here we alloc a big block of memory once and make it - // aligned to page boundary and multiple of page size. This - // is because the memory can be modified by E1000 DMA and - // should be mapped no-cache which will hugely reduce memory - // access performance. The page size alloc will restrict - // this bad effect only within the memory we alloc here. - // - // NEED FIX: the memalign may alloc memory continous in - // virtual address but dis-continous in physical address - // due to RGMP memory setup. - size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) + - CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE + - CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + - CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE; - size = ROUNDUP(size, PGSIZE); - omem = kmem = memalign(PGSIZE, size); - if (kmem == NULL) { - err = -ENOMEM; - goto err1; - } - rgmp_memremap_nocache((uintptr_t)kmem, size); - - // alloc memory for tx ring - dev->tx_ring.desc = (struct tx_desc*)kmem; - kmem += CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc); - dev->tx_ring.buf = kmem; - kmem += CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE; - - // alloc memory for rx rings - dev->rx_ring.desc = (struct rx_desc*)kmem; - kmem += CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc); - dev->rx_ring.buf = kmem; - - /* Initialize the driver structure */ - - dev->uip_dev.d_ifup = e1000_ifup; /* I/F up (new IP address) callback */ - dev->uip_dev.d_ifdown = e1000_ifdown; /* I/F down callback */ - dev->uip_dev.d_txavail = e1000_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - dev->uip_dev.d_addmac = e1000_addmac; /* Add multicast MAC address */ - dev->uip_dev.d_rmmac = e1000_rmmac; /* Remove multicast MAC address */ -#endif - dev->uip_dev.d_private = dev; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - dev->txpoll = wd_create(); /* Create periodic poll timer */ - dev->txtimeout = wd_create(); /* Create TX timeout timer */ - - // Put the interface in the down state. - // e1000 reset - e1000_reset(dev); - - /* Read the MAC address from the hardware */ - memcpy(dev->uip_dev.d_mac.ether_addr_octet, (void *)(dev->io_mem_base+E1000_RA), 6); - - /* Register the device with the OS so that socket IOCTLs can be performed */ - err = netdev_register(&dev->uip_dev); - if (err) - goto err2; - - // insert into e1000_list - dev->next = e1000_list.next; - e1000_list.next = dev; - cprintf("bring up e1000 device: %04x %08x\n", addr, id.join); - - return 0; - -err2: - rgmp_memremap((uintptr_t)omem, size); - free(omem); -err1: - pci_free_irq(addr); -err0: - rgmp_memunmap(mmio_base, mmio_size); -error: - kfree(dev); - cprintf("e1000 device probe fail: %d\n", err); - return err; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -void e1000_mod_init(void) -{ - pci_probe_device(e1000_id_table, e1000_probe); -} - -void e1000_mod_exit(void) -{ - uint32_t size; - struct e1000_dev *dev; - - size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) + - CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE + - CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + - CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE; - size = ROUNDUP(size, PGSIZE); - - for (dev=e1000_list.next; dev!=NULL; dev=dev->next) { - netdev_unregister(&dev->uip_dev); - e1000_reset(dev); - wd_delete(dev->txpoll); - wd_delete(dev->txtimeout); - rgmp_memremap((uintptr_t)dev->tx_ring.desc, size); - free(dev->tx_ring.desc); - pci_free_irq(dev->pci_addr); - rgmp_memunmap((uintptr_t)dev->io_mem_base, dev->mem_size); - kfree(dev); - } - - e1000_list.next = NULL; -} diff --git a/nuttx/drivers/net/e1000.h b/nuttx/drivers/net/e1000.h deleted file mode 100644 index 63ff53e3c..000000000 --- a/nuttx/drivers/net/e1000.h +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** - * drivers/net/e1000.h - * - * Copyright (C) 2011 Yu Qiang. All rights reserved. - * Author: Yu Qiang - * - * This file is a part of NuttX: - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_NET_E1000_H -#define __DRIVERS_NET_E1000_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/************** PCI ID ***************/ - -#define INTEL_VENDERID 0x8086 -#define E1000_82573L 0x109a -#define E1000_82540EM 0x100e -#define E1000_82574L 0x10d3 -#define E1000_82567LM 0x10f5 -#define E1000_82541PI 0x107c - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -enum e1000_registers { - E1000_CTRL = 0x0000, // Device Control - E1000_STATUS = 0x0008, // Device Status - E1000_CTRL_EXT = 0x0018, // Device Control Extension - E1000_FCAL = 0x0028, // Flow Control Address Low - E1000_FCAH = 0x002C, // Flow Control Address High - E1000_FCT = 0x0030, // Flow Control Type - E1000_ICR = 0x00C0, // Interrupt Cause Read - E1000_ICS = 0x00C8, // Interrupt Cause Set - E1000_IMS = 0x00D0, // Interrupt Mask Set - E1000_IMC = 0x00D8, // Interrupt Mask Clear - E1000_RCTL = 0x0100, // Receive Control - E1000_FCTTV = 0x0170, // Flow Control Transmit Timer Value - E1000_TCTL = 0x0400, // Transmit Control - E1000_PBA = 0x1000, // Packet Buffer Allocation - E1000_FCRTL = 0x2160, // Flow Control Receive Threshold Low - E1000_FCRTH = 0x2168, // Flow Control Receive Threshold High - E1000_RDBAL = 0x2800, // Rx Descriptor Base Address Low - E1000_RDBAH = 0x2804, // Rx Descriptor Base Address High - E1000_RDLEN = 0x2808, // Rx Descriptor Length - E1000_RDH = 0x2810, // Rx Descriptor Head - E1000_RDT = 0x2818, // Rx Descriptor Tail - E1000_RXDCTL = 0x2828, // Rx Descriptor Control - E1000_TDBAL = 0x3800, // Tx Descriptor Base Address Low - E1000_TDBAH = 0x3804, // Tx Descriptor Base Address High - E1000_TDLEN = 0x3808, // Tx Descriptor Length - E1000_TDH = 0x3810, // Tx Descriptor Head - E1000_TDT = 0x3818, // Tx Descriptor Tail - E1000_TXDCTL = 0x3828, // Tx Descriptor Control - E1000_TPR = 0x40D0, // Total Packets Received - E1000_TPT = 0x40D4, // Total Packets Transmitted - E1000_RA = 0x5400, // Receive-filter Array -}; - -/***************** e1000 device structure *****************/ - -struct tx_desc { - uint64_t base_address; - uint16_t packet_length; - uint8_t cksum_offset; - uint8_t desc_command; - uint8_t desc_status; - uint8_t cksum_origin; - uint16_t special_info; -}; - -struct rx_desc { - uint64_t base_address; - uint16_t packet_length; - uint16_t packet_cksum; - uint8_t desc_status; - uint8_t desc_errors; - uint16_t vlan_tag; -}; - -#endif diff --git a/nuttx/drivers/net/enc28j60.c b/nuttx/drivers/net/enc28j60.c deleted file mode 100644 index 203259aeb..000000000 --- a/nuttx/drivers/net/enc28j60.c +++ /dev/null @@ -1,2624 +0,0 @@ -/**************************************************************************** - * drivers/net/enc28j60.c - * - * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * - ENC28J60 Data Sheet, Stand-Alone Ethernet Controller with SPI Interface, - * DS39662C, 2008 Microchip Technology Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#if defined(CONFIG_NET) && defined(CONFIG_ENC28J60) - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "enc28j60.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -/* ENC28J60 Configuration Settings: - * - * CONFIG_ENC28J60 - Enabled ENC28J60 support - * CONFIG_ENC28J60_SPIMODE - Controls the SPI mode - * CONFIG_ENC28J60_FREQUENCY - Define to use a different bus frequency - * CONFIG_ENC28J60_NINTERFACES - Specifies the number of physical ENC28J60 - * devices that will be supported. - * CONFIG_ENC28J60_STATS - Collect network statistics - * CONFIG_ENC28J60_HALFDUPPLEX - Default is full duplex - */ - -/* The ENC28J60 spec says that it supports SPI mode 0,0 only: "The - * implementation used on this device supports SPI mode 0,0 only. In - * addition, the SPI port requires that SCK be at Idle in a low state; - * selectable clock polarity is not supported." However, sometimes you - * need to tinker with these things. - */ - -#ifndef CONFIG_ENC28J60_SPIMODE -# define CONFIG_ENC28J60_SPIMODE SPIDEV_MODE0 -#endif - -/* CONFIG_ENC28J60_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_ENC28J60_NINTERFACES -# define CONFIG_ENC28J60_NINTERFACES 1 -#endif - -/* CONFIG_NET_BUFSIZE must always be defined */ - -#if !defined(CONFIG_NET_BUFSIZE) && (CONFIG_NET_BUFSIZE <= MAX_FRAMELEN) -# error "CONFIG_NET_BUFSIZE is not valid for the ENC28J60" -#endif - -/* We need to have the work queue to handle SPI interrupts */ - -#ifndef CONFIG_SCHED_WORKQUEUE -# error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" -#endif - -/* CONFIG_ENC28J60_DUMPPACKET will dump the contents of each packet to the console. */ - -#ifdef CONFIG_ENC28J60_DUMPPACKET -# define enc_dumppacket(m,a,n) lib_dumpbuffer(m,a,n) -#else -# define enc_dumppacket(m,a,n) -#endif - -/* The ENC28J60 will not do interrupt level processing */ - -#ifndef CONFIG_NET_NOINTS -# warrning "CONFIG_NET_NOINTS should be set" -#endif - -/* Low-level register debug */ - -#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET) -# undef CONFIG_ENC28J60_REGDEBUG -#endif - -/* Timing *******************************************************************/ - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define ENC_WDDELAY (1*CLK_TCK) -#define ENC_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define ENC_TXTIMEOUT (60*CLK_TCK) - -/* Poll timeout */ - -#define ENC_POLLTIMEOUT MSEC2TICK(50) - -/* Packet Memory ************************************************************/ - -/* Packet memory layout */ - -#define ALIGNED_BUFSIZE ((CONFIG_NET_BUFSIZE + 255) & ~255) - -#define PKTMEM_TX_START 0x0000 /* Start TX buffer at 0 */ -#define PKTMEM_TX_ENDP1 ALIGNED_BUFSIZE /* Allow TX buffer for one frame */ -#define PKTMEM_RX_START PKTMEM_TX_ENDP1 /* Followed by RX buffer */ -#define PKTMEM_RX_END PKTMEM_END /* RX buffer goes to the end of SRAM */ - -/* Misc. Helper Macros ******************************************************/ - -#define enc_rdgreg(priv,ctrlreg) \ - enc_rdgreg2(priv, ENC_RCR | GETADDR(ctrlreg)) -#define enc_wrgreg(priv,ctrlreg,wrdata) \ - enc_wrgreg2(priv, ENC_WCR | GETADDR(ctrlreg), wrdata) -#define enc_bfcgreg(priv,ctrlreg,clrbits) \ - enc_wrgreg2(priv, ENC_BFC | GETADDR(ctrlreg), clrbits) -#define enc_bfsgreg(priv,ctrlreg,setbits) \ - enc_wrgreg2(priv, ENC_BFS | GETADDR(ctrlreg), setbits) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct uip_eth_hdr *)priv->dev.d_buf) - -/* Debug ********************************************************************/ - -#ifdef CONFIG_ENC28J60_REGDEBUG -# define enc_wrdump(a,v) lowsyslog("ENC28J60: %02x<-%02x\n", a, v); -# define enc_rddump(a,v) lowsyslog("ENC28J60: %02x->%02x\n", a, v); -# define enc_cmddump(c) lowsyslog("ENC28J60: CMD: %02x\n", c); -# define enc_bmdump(c,b,s) lowsyslog("ENC28J60: CMD: %02x buffer: %p length: %d\n", c,b,s); -#else -# define enc_wrdump(a,v) -# define enc_rddump(a,v) -# define enc_cmddump(c) -# define enc_bmdump(c,b,s) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* The state of the interface */ - -enum enc_state_e -{ - ENCSTATE_UNINIT = 0, /* The interface is in an uninitialized state */ - ENCSTATE_DOWN, /* The interface is down */ - ENCSTATE_UP /* The interface is up */ -}; - -/* The enc_driver_s encapsulates all state information for a single hardware - * interface - */ - -struct enc_driver_s -{ - /* Device control */ - - uint8_t ifstate; /* Interface state: See ENCSTATE_* */ - uint8_t bank; /* Currently selected bank */ - uint16_t nextpkt; /* Next packet address */ - FAR const struct enc_lower_s *lower; /* Low-level MCU-specific support */ - - /* Timing */ - - WDOG_ID txpoll; /* TX poll timer */ - WDOG_ID txtimeout; /* TX timeout timer */ - - /* If we don't own the SPI bus, then we cannot do SPI accesses from the - * interrupt handler. - */ - - struct work_s irqwork; /* Interrupt continuation work queue support */ - struct work_s towork; /* Tx timeout work queue support */ - struct work_s pollwork; /* Poll timeout work queue support */ - - /* This is the contained SPI driver intstance */ - - FAR struct spi_dev_s *spi; - - /* This holds the information visible to uIP/NuttX */ - - struct uip_driver_s dev; /* Interface understood by uIP */ - - /* Statistics */ - -#ifdef CONFIG_ENC28J60_STATS - struct enc_stats_s stats; -#endif -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct enc_driver_s g_enc28j60[CONFIG_ENC28J60_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void enc_configspi(FAR struct spi_dev_s *spi); -# define enc_lock(priv); -# define enc_unlock(priv); -#else -# define enc_configspi(spi) -static void enc_lock(FAR struct enc_driver_s *priv); -static inline void enc_unlock(FAR struct enc_driver_s *priv); -#endif - -/* SPI control register access */ - -static uint8_t enc_rdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd); -static void enc_wrgreg2(FAR struct enc_driver_s *priv, uint8_t cmd, - uint8_t wrdata); -static inline void enc_src(FAR struct enc_driver_s *priv); -static void enc_setbank(FAR struct enc_driver_s *priv, uint8_t bank); -static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg); -static void enc_wrbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, - uint8_t wrdata); -static int enc_waitbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, - uint8_t bits, uint8_t value); - -#if 0 /* Sometimes useful */ -static void enc_rxdump(FAR struct enc_driver_s *priv); -static void enc_txdump(FAR struct enc_driver_s *priv); -#endif - -/* SPI buffer transfers */ - -static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer, - size_t buflen); -static inline void enc_wrbuffer(FAR struct enc_driver_s *priv, - FAR const uint8_t *buffer, size_t buflen); - -/* PHY register access */ - -static uint16_t enc_rdphy(FAR struct enc_driver_s *priv, uint8_t phyaddr); -static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr, - uint16_t phydata); - -/* Common TX logic */ - -static int enc_transmit(FAR struct enc_driver_s *priv); -static int enc_uiptxpoll(struct uip_driver_s *dev); - -/* Interrupt handling */ - -static void enc_linkstatus(FAR struct enc_driver_s *priv); -static void enc_txif(FAR struct enc_driver_s *priv); -static void enc_txerif(FAR struct enc_driver_s *priv); -static void enc_txerif(FAR struct enc_driver_s *priv); -static void enc_rxerif(FAR struct enc_driver_s *priv); -static void enc_rxdispatch(FAR struct enc_driver_s *priv); -static void enc_pktif(FAR struct enc_driver_s *priv); -static void enc_irqworker(FAR void *arg); -static int enc_interrupt(int irq, FAR void *context); - -/* Watchdog timer expirations */ - -static void enc_toworker(FAR void *arg); -static void enc_txtimeout(int argc, uint32_t arg, ...); -static void enc_pollworker(FAR void *arg); -static void enc_polltimer(int argc, uint32_t arg, ...); - -/* NuttX callback functions */ - -static int enc_ifup(struct uip_driver_s *dev); -static int enc_ifdown(struct uip_driver_s *dev); -static int enc_txavail(struct uip_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int enc_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -static int enc_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -#endif - -/* Initialization */ - -static void enc_pwrsave(FAR struct enc_driver_s *priv); -static void enc_pwrfull(FAR struct enc_driver_s *priv); -static void enc_setmacaddr(FAR struct enc_driver_s *priv); -static int enc_reset(FAR struct enc_driver_s *priv); - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: enc_configspi - * - * Description: - * Configure the SPI for use with the ENC28J60 - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void enc_configspi(FAR struct spi_dev_s *spi) -{ - /* Configure SPI for the ENC28J60. But only if we own the SPI bus. - * Otherwise, don't bother because it might change. - */ - - SPI_SETMODE(spi, CONFIG_ENC28J60_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_ENC28J60_FREQUENCY) -} -#endif - -/**************************************************************************** - * Function: enc_lock - * - * Description: - * Select the SPI, locking and re-configuring if necessary - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void enc_lock(FAR struct enc_driver_s *priv) -{ - /* Lock the SPI bus in case there are multiple devices competing for the SPI - * bus. - */ - - SPI_LOCK(priv->spi, true); - - /* Now make sure that the SPI bus is configured for the ENC28J60 (it - * might have gotten configured for a different device while unlocked) - */ - - SPI_SETMODE(priv->spi, CONFIG_ENC28J60_SPIMODE); - SPI_SETBITS(priv->spi, 8); - SPI_SETFREQUENCY(priv->spi, CONFIG_ENC28J60_FREQUENCY); -} -#endif - -/**************************************************************************** - * Function: enc_unlock - * - * Description: - * De-select the SPI - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static inline void enc_unlock(FAR struct enc_driver_s *priv) -{ - /* Relinquish the lock on the bus. */ - - SPI_LOCK(priv->spi, false); -} -#endif - -/**************************************************************************** - * Function: enc_rdgreg2 - * - * Description: - * Read a global register (EIE, EIR, ESTAT, ECON2, or ECON1). The cmd - * include the CMD 'OR'd with the the global address register. - * - * Parameters: - * priv - Reference to the driver state structure - * cmd - The full command to received (cmd | address) - * - * Returned Value: - * The value read from the register - * - * Assumptions: - * - ****************************************************************************/ - -static uint8_t enc_rdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd) -{ - uint8_t rddata; - - DEBUGASSERT(priv && priv->spi); - - /* Select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the read command and collect the data. The sequence requires - * 16-clocks: 8 to clock out the cmd + 8 to clock in the data. - */ - - (void)SPI_SEND(priv->spi, cmd); /* Clock out the command */ - rddata = SPI_SEND(priv->spi, 0); /* Clock in the data */ - - /* De-select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - - enc_rddump(cmd, rddata); - return rddata; -} - -/**************************************************************************** - * Function: enc_wrgreg2 - * - * Description: - * Write to a global register (EIE, EIR, ESTAT, ECON2, or ECON1). The cmd - * include the CMD 'OR'd with the the global address register. - * - * Parameters: - * priv - Reference to the driver state structure - * cmd - The full command to received (cmd | address) - * wrdata - The data to send - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_wrgreg2(FAR struct enc_driver_s *priv, uint8_t cmd, - uint8_t wrdata) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the write command and data. The sequence requires 16-clocks: - * 8 to clock out the cmd + 8 to clock out the data. - */ - - (void)SPI_SEND(priv->spi, cmd); /* Clock out the command */ - (void)SPI_SEND(priv->spi, wrdata); /* Clock out the data */ - - /* De-select ENC28J60 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_wrdump(cmd, wrdata); -} - -/**************************************************************************** - * Function: enc_src - * - * Description: - * Send the single byte system reset command (SRC). - * - * "The System Reset Command (SRC) allows the host controller to issue a - * System Soft Reset command. Unlike other SPI commands, the SRC is - * only a single byte command and does not operate on any register. The - * command is started by pulling the CS pin low. The SRC opcode is the - * sent, followed by a 5-bit Soft Reset command constant of 1Fh. The - * SRC operation is terminated by raising the CS pin." - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static inline void enc_src(FAR struct enc_driver_s *priv) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the system reset command. */ - - (void)SPI_SEND(priv->spi, ENC_SRC); - - /* Check CLKRDY bit to see when the reset is complete. There is an errata - * that says the CLKRDY may be invalid. We'll wait a couple of msec to - * workaround this condition. - * - * Also, "After a System Reset, all PHY registers should not be read or - * written to until at least 50 µs have passed since the Reset has ended. - * All registers will revert to their Reset default values. The dual - * port buffer memory will maintain state throughout the System Reset." - */ - - up_mdelay(2); - /* while ((enc_rdgreg(priv, ENC_ESTAT) & ESTAT_CLKRDY) != 0); */ - - /* De-select ENC28J60 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_cmddump(ENC_SRC); -} - -/**************************************************************************** - * Function: enc_setbank - * - * Description: - * Set the bank for these next control register access. - * - * Assumption: - * The caller has exclusive access to the SPI bus - * - * Parameters: - * priv - Reference to the driver state structure - * bank - The bank to select (0-3) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_setbank(FAR struct enc_driver_s *priv, uint8_t bank) -{ - /* Check if the bank setting has changed*/ - - if (bank != priv->bank) - { - /* Select bank 0 (just so that all of the bits are cleared) */ - - enc_bfcgreg(priv, ENC_ECON1, ECON1_BSEL_MASK); - - /* Then OR in bits to get the correct bank */ - - if (bank != 0) - { - enc_bfsgreg(priv, ENC_ECON1, (bank << ECON1_BSEL_SHIFT)); - } - - /* Then remember the bank setting */ - - priv->bank = bank; - } -} - -/**************************************************************************** - * Function: enc_rdbreg - * - * Description: - * Read from a banked control register using the RCR command. - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to read - * - * Returned Value: - * The byte read from the banked register - * - * Assumptions: - * - ****************************************************************************/ - -static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg) -{ - uint8_t rddata; - - DEBUGASSERT(priv && priv->spi); - - /* Set the bank */ - - enc_setbank(priv, GETBANK(ctrlreg)); - - /* Re-select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the RCR command and collect the data. How we collect the data - * depends on if this is a PHY/CAN or not. The normal sequence requires - * 16-clocks: 8 to clock out the cmd and 8 to clock in the data. - */ - - (void)SPI_SEND(priv->spi, ENC_RCR | GETADDR(ctrlreg)); /* Clock out the command */ - if (ISPHYMAC(ctrlreg)) - { - /* The PHY/MAC sequence requires 24-clocks: 8 to clock out the cmd, - * 8 dummy bits, and 8 to clock in the PHY/MAC data. - */ - - (void)SPI_SEND(priv->spi, 0); /* Clock in the dummy byte */ - } - - rddata = SPI_SEND(priv->spi, 0); /* Clock in the data */ - - /* De-select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_rddump(ENC_RCR | GETADDR(ctrlreg), rddata); - return rddata; -} - -/**************************************************************************** - * Function: enc_wrbreg - * - * Description: - * Write to a banked control register using the WCR command. Unlike - * reading, this same SPI sequence works for normal, MAC, and PHY - * registers. - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to write - * wrdata - The data to send - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_wrbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, - uint8_t wrdata) -{ - DEBUGASSERT(priv && priv->spi); - - /* Set the bank */ - - enc_setbank(priv, GETBANK(ctrlreg)); - - /* Re-select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the WCR command and data. The sequence requires 16-clocks: - * 8 to clock out the cmd + 8 to clock out the data. - */ - - (void)SPI_SEND(priv->spi, ENC_WCR | GETADDR(ctrlreg)); /* Clock out the command */ - (void)SPI_SEND(priv->spi, wrdata); /* Clock out the data */ - - /* De-select ENC28J60 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_wrdump(ENC_WCR | GETADDR(ctrlreg), wrdata); -} - -/**************************************************************************** - * Function: enc_waitbreg - * - * Description: - * Wait until banked register bit(s) take a specific value (or a timeout - * occurs). - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to check - * bits - The bits to check (a mask) - * value - The value of the bits to return (value under mask) - * - * Returned Value: - * OK on success, negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_waitbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, - uint8_t bits, uint8_t value) -{ - uint32_t start = clock_systimer(); - uint32_t elapsed; - uint8_t rddata; - - /* Loop until the exit condition is met */ - - do - { - /* Read the byte from the requested banked register */ - - rddata = enc_rdbreg(priv, ctrlreg); - elapsed = clock_systimer() - start; - } - while ((rddata & bits) != value || elapsed > ENC_POLLTIMEOUT); - - return (rddata & bits) == value ? -ETIMEDOUT : OK; -} - -/**************************************************************************** - * Function: enc_txdump enc_rxdump - * - * Description: - * Dump registers associated with receiving or sending packets. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#if 0 /* Sometimes useful */ -static void enc_rxdump(FAR struct enc_driver_s *priv) -{ - lowsyslog("Rx Registers:\n"); - lowsyslog(" EIE: %02x EIR: %02x\n", - enc_rdgreg(priv, ENC_EIE), enc_rdgreg(priv, ENC_EIR)); - lowsyslog(" ESTAT: %02x ECON1: %02x ECON2: %02x\n", - enc_rdgreg(priv, ENC_ESTAT), enc_rdgreg(priv, ENC_ECON1), - enc_rdgreg(priv, ENC_ECON2)); - lowsyslog(" ERXST: %02x %02x\n", - enc_rdbreg(priv, ENC_ERXSTH), enc_rdbreg(priv, ENC_ERXSTL)); - lowsyslog(" ERXND: %02x %02x\n", - enc_rdbreg(priv, ENC_ERXNDH), enc_rdbreg(priv, ENC_ERXNDL)); - lowsyslog(" ERXRDPT: %02x %02x\n", - enc_rdbreg(priv, ENC_ERXRDPTH), enc_rdbreg(priv, ENC_ERXRDPTL)); - lowsyslog(" ERXFCON: %02x EPKTCNT: %02x\n", - enc_rdbreg(priv, ENC_ERXFCON), enc_rdbreg(priv, ENC_EPKTCNT)); - lowsyslog(" MACON1: %02x MACON3: %02x\n", - enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3)); - lowsyslog(" MAMXFL: %02x %02x\n", - enc_rdbreg(priv, ENC_MAMXFLH), enc_rdbreg(priv, ENC_MAMXFLL)); - lowsyslog(" MAADR: %02x:%02x:%02x:%02x:%02x:%02x\n", - enc_rdbreg(priv, ENC_MAADR1), enc_rdbreg(priv, ENC_MAADR2), - enc_rdbreg(priv, ENC_MAADR3), enc_rdbreg(priv, ENC_MAADR4), - enc_rdbreg(priv, ENC_MAADR5), enc_rdbreg(priv, ENC_MAADR6)); -} -#endif - -#if 0 /* Sometimes useful */ -static void enc_txdump(FAR struct enc_driver_s *priv) -{ - lowsyslog("Tx Registers:\n"); - lowsyslog(" EIE: %02x EIR: %02x ESTAT: %02x\n", - enc_rdgreg(priv, ENC_EIE), enc_rdgreg(priv, ENC_EIR),); - lowsyslog(" ESTAT: %02x ECON1: %02x\n", - enc_rdgreg(priv, ENC_ESTAT), enc_rdgreg(priv, ENC_ECON1)); - lowsyslog(" ETXST: %02x %02x\n", - enc_rdbreg(priv, ENC_ETXSTH), enc_rdbreg(priv, ENC_ETXSTL)); - lowsyslog(" ETXND: %02x %02x\n", - enc_rdbreg(priv, ENC_ETXNDH), enc_rdbreg(priv, ENC_ETXNDL)); - lowsyslog(" MACON1: %02x MACON3: %02x MACON4: %02x\n", - enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3), - enc_rdbreg(priv, ENC_MACON4)); - lowsyslog(" MACON1: %02x MACON3: %02x MACON4: %02x\n", - enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3), - enc_rdbreg(priv, ENC_MACON4)); - lowsyslog(" MABBIPG: %02x MAIPG %02x %02x\n", - enc_rdbreg(priv, ENC_MABBIPG), enc_rdbreg(priv, ENC_MAIPGH), - enc_rdbreg(priv, ENC_MAIPGL)); - lowsyslog(" MACLCON1: %02x MACLCON2: %02x\n", - enc_rdbreg(priv, ENC_MACLCON1), enc_rdbreg(priv, ENC_MACLCON2)); - lowsyslog(" MAMXFL: %02x %02x\n", - enc_rdbreg(priv, ENC_MAMXFLH), enc_rdbreg(priv, ENC_MAMXFLL)); -} -#endif - -/**************************************************************************** - * Function: enc_rdbuffer - * - * Description: - * Read a buffer of data. - * - * Parameters: - * priv - Reference to the driver state structure - * buffer - A pointer to the buffer to read into - * buflen - The number of bytes to read - * - * Returned Value: - * None - * - * Assumptions: - * Read pointer is set to the correct address - * - ****************************************************************************/ - -static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer, - size_t buflen) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the read buffer memory command (ignoring the response) */ - - (void)SPI_SEND(priv->spi, ENC_RBM); - - /* Then read the buffer data */ - - SPI_RECVBLOCK(priv->spi, buffer, buflen); - - /* De-select ENC28J60 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_bmdump(ENC_WBM, buffer, buflen); -} - -/**************************************************************************** - * Function: enc_wrbuffer - * - * Description: - * Write a buffer of data. - * - * Parameters: - * priv - Reference to the driver state structure - * buffer - A pointer to the buffer to write from - * buflen - The number of bytes to write - * - * Returned Value: - * None - * - * Assumptions: - * Read pointer is set to the correct address - * - ****************************************************************************/ - -static inline void enc_wrbuffer(FAR struct enc_driver_s *priv, - FAR const uint8_t *buffer, size_t buflen) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENC28J60 chip - * - * "The WBM command is started by lowering the CS pin. ..." - */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the write buffer memory command (ignoring the response) - * - * "...The [3-bit]WBM opcode should then be sent to the ENC28J60, - * followed by the 5-bit constant, 1Ah." - */ - - (void)SPI_SEND(priv->spi, ENC_WBM); - - /* "...the ENC28J60 requires a single per packet control byte to - * precede the packet for transmission." - * - * POVERRIDE: Per Packet Override bit (Not set): - * 1 = The values of PCRCEN, PPADEN and PHUGEEN will override the - * configuration defined by MACON3. - * 0 = The values in MACON3 will be used to determine how the packet - * will be transmitted - * PCRCEN: Per Packet CRC Enable bit (Set, but won't be used because - * POVERRIDE is zero). - * PPADEN: Per Packet Padding Enable bit (Set, but won't be used because - * POVERRIDE is zero). - * PHUGEEN: Per Packet Huge Frame Enable bit (Set, but won't be used - * because POVERRIDE is zero). - */ - - (void)SPI_SEND(priv->spi, - (PKTCTRL_PCRCEN | PKTCTRL_PPADEN | PKTCTRL_PHUGEEN)); - - /* Then send the buffer - * - * "... After the WBM command and constant are sent, the data to - * be stored in the memory pointed to by EWRPT should be shifted - * out MSb first to the ENC28J60. After 8 data bits are received, - * the Write Pointer will automatically increment if AUTOINC is - * set. The host controller can continue to provide clocks on the - * SCK pin and send data on the SI pin, without raising CS, to - * keep writing to the memory. In this manner, with AUTOINC - * enabled, it is possible to continuously write sequential bytes - * to the buffer memory without any extra SPI command - * overhead. - */ - - SPI_SNDBLOCK(priv->spi, buffer, buflen); - - /* De-select ENC28J60 chip - * - * "The WBM command is terminated by bringing up the CS pin. ..." - */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_bmdump(ENC_WBM, buffer, buflen+1); -} - -/**************************************************************************** - * Function: enc_rdphy - * - * Description: - * Read 16-bits of PHY data. - * - * Parameters: - * priv - Reference to the driver state structure - * phyaddr - The PHY register address - * - * Returned Value: - * 16-bit value read from the PHY - * - * Assumptions: - * - ****************************************************************************/ - -static uint16_t enc_rdphy(FAR struct enc_driver_s *priv, uint8_t phyaddr) -{ - uint16_t data = 0; - - /* "To read from a PHY register: - * - * 1. Write the address of the PHY register to read from into the MIREGADR - * register. - */ - - enc_wrbreg(priv, ENC_MIREGADR, phyaddr); - - /* 2. Set the MICMD.MIIRD bit. The read operation begins and the - * MISTAT.BUSY bit is set. - */ - - enc_wrbreg(priv, ENC_MICMD, MICMD_MIIRD); - - /* 3. Wait 10.24 µs. Poll the MISTAT.BUSY bit to be certain that the - * operation is complete. While busy, the host controller should not - * start any MIISCAN operations or write to the MIWRH register. - * - * When the MAC has obtained the register contents, the BUSY bit will - * clear itself. - */ - - up_udelay(12); - if (enc_waitbreg(priv, ENC_MISTAT, MISTAT_BUSY, 0x00) == OK); - { - /* 4. Clear the MICMD.MIIRD bit. */ - - enc_wrbreg(priv, ENC_MICMD, 0x00); - - /* 5. Read the desired data from the MIRDL and MIRDH registers. The - * order that these bytes are accessed is unimportant." - */ - - data = (uint16_t)enc_rdbreg(priv, ENC_MIRDL); - data |= (uint16_t)enc_rdbreg(priv, ENC_MIRDH) << 8; - } - - return data; -} - -/**************************************************************************** - * Function: enc_wrphy - * - * Description: - * write 16-bits of PHY data. - * - * Parameters: - * priv - Reference to the driver state structure - * phyaddr - The PHY register address - * phydata - 16-bit data to write to the PHY - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr, - uint16_t phydata) -{ - /* "To write to a PHY register: - * - * 1. Write the address of the PHY register to write to into the - * MIREGADR register. - */ - - enc_wrbreg(priv, ENC_MIREGADR, phyaddr); - - /* 2. Write the lower 8 bits of data to write into the MIWRL register. */ - - enc_wrbreg(priv, ENC_MIWRL, phydata); - - /* 3. Write the upper 8 bits of data to write into the MIWRH register. - * Writing to this register automatically begins the MIIM transaction, - * so it must be written to after MIWRL. The MISTAT.BUSY bit becomes - * set. - */ - - enc_wrbreg(priv, ENC_MIWRH, phydata >> 8); - - /* The PHY register will be written after the MIIM operation completes, - * which takes 10.24 µs. When the write operation has completed, the BUSY - * bit will clear itself. - * - * The host controller should not start any MIISCAN or MIIRD operations - * while busy." - */ - - up_udelay(12); - enc_waitbreg(priv, ENC_MISTAT, MISTAT_BUSY, 0x00); -} - -/**************************************************************************** - * Function: enc_transmit - * - * Description: - * Start hardware transmission. Called either from: - * - * - pkif interrupt when an application responds to the receipt of data - * by trying to send something, or - * - From watchdog based polling. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_transmit(FAR struct enc_driver_s *priv) -{ - uint16_t txend; - - /* Increment statistics */ - - nllvdbg("Sending packet, pktlen: %d\n", priv->dev.d_len); -#ifdef CONFIG_ENC28J60_STATS - priv->stats.txrequests++; -#endif - - /* Verify that the hardware is ready to send another packet. The driver - * starts a transmission process by setting ECON1.TXRTS. When the packet is - * finished transmitting or is aborted due to an error/cancellation, the - * ECON1.TXRTS bit will be cleared. - * - * NOTE: If we got here, then we have committed to sending a packet. - * higher level logic must have assured that (1) there is no transmission - * in progress, and that (2) TX-related interrupts are disabled. - */ - - DEBUGASSERT((enc_rdgreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0); - - /* Send the packet: address=priv->dev.d_buf, length=priv->dev.d_len */ - - enc_dumppacket("Transmit Packet", priv->dev.d_buf, priv->dev.d_len); - - /* Set transmit buffer start (is this necessary?). */ - - enc_wrbreg(priv, ENC_ETXSTL, PKTMEM_TX_START & 0xff); - enc_wrbreg(priv, ENC_ETXSTH, PKTMEM_TX_START >> 8); - - /* Reset the write pointer to start of transmit buffer */ - - enc_wrbreg(priv, ENC_EWRPTL, PKTMEM_TX_START & 0xff); - enc_wrbreg(priv, ENC_EWRPTH, PKTMEM_TX_START >> 8); - - /* Set the TX End pointer based on the size of the packet to send. Note - * that the offset accounts for the control byte at the beginning the - * buffer plus the size of the packet data. - */ - - txend = PKTMEM_TX_START + priv->dev.d_len; - enc_wrbreg(priv, ENC_ETXNDL, txend & 0xff); - enc_wrbreg(priv, ENC_ETXNDH, txend >> 8); - - /* Send the WBM command and copy the packet itself into the transmit - * buffer at the position of the EWRPT register. - */ - - enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len); - - /* Set TXRTS to send the packet in the transmit buffer */ - - enc_bfsgreg(priv, ENC_ECON1, ECON1_TXRTS); - - /* Setup the TX timeout watchdog (perhaps restarting the timer). Note: - * Is there a race condition. Could the TXIF interrupt occur before - * the timer is started? - */ - - (void)wd_start(priv->txtimeout, ENC_TXTIMEOUT, enc_txtimeout, 1, (uint32_t)priv); - return OK; -} - -/**************************************************************************** - * Function: enc_uiptxpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from uip_poll(). uip_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static int enc_uiptxpoll(struct uip_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - nllvdbg("Poll result: d_len=%d\n", priv->dev.d_len); - if (priv->dev.d_len > 0) - { - uip_arp_out(&priv->dev); - enc_transmit(priv); - - /* Stop the poll now because we can queue only one packet */ - - return -EBUSY; - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return OK; -} - -/**************************************************************************** - * Function: enc_linkstatus - * - * Description: - * The current link status can be obtained from the PHSTAT1.LLSTAT or - * PHSTAT2.LSTAT. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_linkstatus(FAR struct enc_driver_s *priv) -{ -#if 0 - uint16_t regval = enc_rdphy(priv, ENC_PHSTAT2); - priv->duplex = ((regval & PHSTAT2_DPXSTAT) != 0); - priv->carrier = ((regval & PHSTAT2_LSTAT) != 0); -#endif -} - -/**************************************************************************** - * Function: enc_txif - * - * Description: - * An TXIF interrupt was received indicating that the last TX packet(s) is - * done - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_txif(FAR struct enc_driver_s *priv) -{ - /* Update statistics */ - -#ifdef CONFIG_ENC28J60_STATS - priv->stats.txifs++; - if (enc_rdgreg(priv, ENC_ESTAT) & ESTAT_TXABRT) - { - priv->stats.txabrts++; - } -#endif - - /* Clear the request to send bit */ - - enc_bfcgreg(priv, ENC_ECON1, ECON1_TXRTS); - - /* If no further xmits are pending, then cancel the TX timeout */ - - wd_cancel(priv->txtimeout); - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&priv->dev, enc_uiptxpoll); -} - -/**************************************************************************** - * Function: enc_txerif - * - * Description: - * An TXERIF interrupt was received indicating that a TX abort has occurred. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_txerif(FAR struct enc_driver_s *priv) -{ - /* Update statistics */ - -#ifdef CONFIG_ENC28J60_STATS - priv->stats.txerifs++; -#endif - - /* Reset TX */ - - enc_bfsgreg(priv, ENC_ECON1, ECON1_TXRST); - enc_bfcgreg(priv, ENC_ECON1, ECON1_TXRST | ECON1_TXRTS); - - /* Here we really should re-transmit (I fact, if we want half duplex to - * work right, then it is necessary to do this!): - * - * 1. Read the TSV: - * - Read ETXNDL to get the end pointer - * - Read 7 bytes from that pointer + 1 using ENC_RMB. - * 2. Determine if we need to retransmit. Check the LATE COLLISION bit, if - * set, then we need to transmit. - * 3. Retranmit by resetting ECON1_TXRTS. - */ - -#ifdef CONFIG_ENC28J60_HALFDUPLEX -# error "Missing logic for half duplex" -#endif -} - -/**************************************************************************** - * Function: enc_rxerif - * - * Description: - * An RXERIF interrupt was received indicating that the last TX packet(s) is - * done - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_rxerif(FAR struct enc_driver_s *priv) -{ - /* Update statistics */ - -#ifdef CONFIG_ENC28J60_STATS - priv->stats.rxerifs++; -#endif -} - -/**************************************************************************** - * Function: enc_rxdispatch - * - * Description: - * Give the newly received packet to uIP. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_rxdispatch(FAR struct enc_driver_s *priv) -{ - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(UIP_ETHTYPE_IP6)) -#else - if (BUF->type == HTONS(UIP_ETHTYPE_IP)) -#endif - { - nllvdbg("IP packet received (%02x)\n", BUF->type); - uip_arp_ipin(&priv->dev); - uip_input(&priv->dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (priv->dev.d_len > 0) - { - uip_arp_out(&priv->dev); - enc_transmit(priv); - } - } - else if (BUF->type == htons(UIP_ETHTYPE_ARP)) - { - nllvdbg("ARP packet received (%02x)\n", BUF->type); - uip_arp_arpin(&priv->dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (priv->dev.d_len > 0) - { - enc_transmit(priv); - } - } - else - { - nlldbg("Unsupported packet type dropped (%02x)\n", htons(BUF->type)); - } -} - -/**************************************************************************** - * Function: enc_pktif - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_pktif(FAR struct enc_driver_s *priv) -{ - uint8_t rsv[6]; - uint16_t pktlen; - uint16_t rxstat; - - /* Update statistics */ - -#ifdef CONFIG_ENC28J60_STATS - priv->stats.pktifs++; -#endif - - /* Set the read pointer to the start of the received packet (ERDPT) */ - - DEBUGASSERT(priv->nextpkt <= PKTMEM_RX_END); - enc_wrbreg(priv, ENC_ERDPTL, (priv->nextpkt)); - enc_wrbreg(priv, ENC_ERDPTH, (priv->nextpkt) >> 8); - - /* Read the next packet pointer and the 4 byte read status vector (RSV) - * at the beginning of the received packet. (ERDPT should auto-increment - * and wrap to the beginning of the read buffer as necessary) - */ - - enc_rdbuffer(priv, rsv, 6); - - /* Decode the new next packet pointer, and the RSV. The - * RSV is encoded as: - * - * Bits 0-15: Indicates length of the received frame. This includes the - * destination address, source address, type/length, data, - * padding and CRC fields. This field is stored in little- - * endian format. - * Bits 16-31: Bit encoded RX status. - */ - - priv->nextpkt = (uint16_t)rsv[1] << 8 | (uint16_t)rsv[0]; - pktlen = (uint16_t)rsv[3] << 8 | (uint16_t)rsv[2]; - rxstat = (uint16_t)rsv[5] << 8 | (uint16_t)rsv[4]; - - nllvdbg("Receiving packet, nextpkt: %04x pktlen: %d rxstat: %04x\n", - priv->nextpkt, pktlen, rxstat); - - /* Check if the packet was received OK */ - - if ((rxstat & RXSTAT_OK) == 0) - { - nlldbg("ERROR: RXSTAT: %04x\n", rxstat); -#ifdef CONFIG_ENC28J60_STATS - priv->stats.rxnotok++; -#endif - } - - /* Check for a usable packet length (4 added for the CRC) */ - - else if (pktlen > (CONFIG_NET_BUFSIZE + 4) || pktlen <= (UIP_LLH_LEN + 4)) - { - nlldbg("Bad packet size dropped (%d)\n", pktlen); -#ifdef CONFIG_ENC28J60_STATS - priv->stats.rxpktlen++; -#endif - } - - /* Otherwise, read and process the packet */ - - else - { - /* Save the packet length (without the 4 byte CRC) in priv->dev.d_len*/ - - priv->dev.d_len = pktlen - 4; - - /* Copy the data data from the receive buffer to priv->dev.d_buf. - * ERDPT should be correctly positioned from the last call to to - * end_rdbuffer (above). - */ - - enc_rdbuffer(priv, priv->dev.d_buf, priv->dev.d_len); - enc_dumppacket("Received Packet", priv->dev.d_buf, priv->dev.d_len); - - /* Dispatch the packet to uIP */ - - enc_rxdispatch(priv); - } - - /* Move the RX read pointer to the start of the next received packet. - * This frees the memory we just read. - */ - - enc_wrbreg(priv, ENC_ERXRDPTL, (priv->nextpkt)); - enc_wrbreg(priv, ENC_ERXRDPTH, (priv->nextpkt) >> 8); - - /* Decrement the packet counter indicate we are done with this packet */ - - enc_bfsgreg(priv, ENC_ECON2, ECON2_PKTDEC); -} - -/**************************************************************************** - * Function: enc_irqworker - * - * Description: - * Perform interrupt handling logic outside of the interrupt handler (on - * the work queue thread). - * - * Parameters: - * arg - The reference to the driver structure (case to void*) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_irqworker(FAR void *arg) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - uip_lock_t lock; - uint8_t eir; - - DEBUGASSERT(priv); - - /* Get exclusive access to both uIP and the SPI bus. */ - - lock = uip_lock(); - enc_lock(priv); - - /* Disable further interrupts by clearing the global interrupt enable bit. - * "After an interrupt occurs, the host controller should clear the global - * enable bit for the interrupt pin before servicing the interrupt. Clearing - * the enable bit will cause the interrupt pin to return to the non-asserted - * state (high). Doing so will prevent the host controller from missing a - * falling edge should another interrupt occur while the immediate interrupt - * is being serviced." - */ - - enc_bfcgreg(priv, ENC_EIE, EIE_INTIE); - - /* Loop until all interrupts have been processed (EIR==0). Note that - * there is no infinite loop check... if there are always pending interrupts, - * we are just broken. - */ - - while ((eir = enc_rdgreg(priv, ENC_EIR) & EIR_ALLINTS) != 0) - { - /* Handle interrupts according to interrupt register register bit - * settings. - */ - - nllvdbg("EIR: %02x\n", eir); - - /* DMAIF: The DMA interrupt indicates that the DMA module has completed - * its memory copy or checksum calculation. Additionally, this interrupt - * will be caused if the host controller cancels a DMA operation by - * manually clearing the DMAST bit. Once set, DMAIF can only be cleared - * by the host controller or by a Reset condition. - */ - - if ((eir & EIR_DMAIF) != 0) /* DMA interrupt */ - { - /* Not used by this driver. Just clear the interrupt request. */ - - enc_bfcgreg(priv, ENC_EIR, EIR_DMAIF); - } - - /* LINKIF: The LINKIF indicates that the link status has changed. - * The actual current link status can be obtained from the - * PHSTAT1.LLSTAT or PHSTAT2.LSTAT. Unlike other interrupt sources, the - * link status change interrupt is created in the integrated PHY - * module. - * - * To receive it, the host controller must set the PHIE.PLNKIE and - * PGEIE bits. After setting the two PHY interrupt enable bits, the - * LINKIF bit will then shadow the contents of the PHIR.PGIF bit. - * - * Once LINKIF is set, it can only be cleared by the host controller or - * by a Reset. The LINKIF bit is read-only. Performing an MII read on - * the PHIR register will clear the LINKIF, PGIF and PLNKIF bits - * automatically and allow for future link status change interrupts. - */ - - if ((eir & EIR_LINKIF) != 0) /* Link change interrupt */ - { - enc_linkstatus(priv); /* Get current link status */ - enc_rdphy(priv, ENC_PHIR); /* Clear the LINKIF interrupt */ - } - - /* TXIF: The Transmit Interrupt Flag (TXIF) is used to indicate that - * the requested packet transmission has ended. Upon transmission - * completion, abort or transmission cancellation by the host - * controller, the EIR.TXIF flag will be set to 1. - * - * Once TXIF is set, it can only be cleared by the host controller - * or by a Reset condition. Once processed, the host controller should - * use the BFC command to clear the EIR.TXIF bit. - */ - - if ((eir & EIR_TXIF) != 0) /* Transmit interrupt */ - { - enc_txif(priv); /* Handle TX completion */ - enc_bfcgreg(priv, ENC_EIR, EIR_TXIF); /* Clear the TXIF interrupt */ - } - - /* TXERIF: The Transmit Error Interrupt Flag (TXERIF) is used to - * indicate that a transmit abort has occurred. An abort can occur - * because of any of the following: - * - * 1. Excessive collisions occurred as defined by the Retransmission - * Maximum (RETMAX) bits in the MACLCON1 register. - * 2. A late collision occurred as defined by the Collision Window - * (COLWIN) bits in the MACLCON2 register. - * 3. A collision after transmitting 64 bytes occurred (ESTAT.LATECOL - * set). - * 4. The transmission was unable to gain an opportunity to transmit - * the packet because the medium was constantly occupied for too long. - * The deferral limit (2.4287 ms) was reached and the MACON4.DEFER bit - * was clear. - * 5. An attempt to transmit a packet larger than the maximum frame - * length defined by the MAMXFL registers was made without setting - * the MACON3.HFRMEN bit or per packet POVERRIDE and PHUGEEN bits. - * - * Upon any of these conditions, the EIR.TXERIF flag is set to 1. Once - * set, it can only be cleared by the host controller or by a Reset - * condition. - * - * After a transmit abort, the TXRTS bit will be cleared, the - * ESTAT.TXABRT bit will be set and the transmit status vector will be - * written at ETXND + 1. The MAC will not automatically attempt to - * retransmit the packet. The host controller may wish to read the - * transmit status vector and LATECOL bit to determine the cause of - * the abort. After determining the problem and solution, the host - * controller should clear the LATECOL (if set) and TXABRT bits so - * that future aborts can be detected accurately. - * - * In Full-Duplex mode, condition 5 is the only one that should cause - * this interrupt. Collisions and other problems related to sharing - * the network are not possible on full-duplex networks. The conditions - * which cause the transmit error interrupt meet the requirements of the - * transmit interrupt. As a result, when this interrupt occurs, TXIF - * will also be simultaneously set. - */ - - if ((eir & EIR_TXERIF) != 0) /* Transmit Error Interrupts */ - { - enc_txerif(priv); /* Handle the TX error */ - enc_bfcgreg(priv, ENC_EIR, EIR_TXERIF); /* Clear the TXERIF interrupt */ - } - - /* PKTIF The Receive Packet Pending Interrupt Flag (PKTIF) is used to - * indicate the presence of one or more data packets in the receive - * buffer and to provide a notification means for the arrival of new - * packets. When the receive buffer has at least one packet in it, - * EIR.PKTIF will be set. In other words, this interrupt flag will be - * set anytime the Ethernet Packet Count register (EPKTCNT) is non-zero. - * - * The PKTIF bit can only be cleared by the host controller or by a Reset - * condition. In order to clear PKTIF, the EPKTCNT register must be - * decremented to 0. If the last data packet in the receive buffer is - * processed, EPKTCNT will become zero and the PKTIF bit will automatically - * be cleared. - */ - - /* Ignore PKTIF because is unreliable. Use EPKTCNT instead */ - /* if ((eir & EIR_PKTIF) != 0) */ - { - uint8_t pktcnt = enc_rdbreg(priv, ENC_EPKTCNT); - if (pktcnt > 0) - { - nllvdbg("EPKTCNT: %02x\n", pktcnt); - -#ifdef CONFIG_ENC28J60_STATS - if (pktcnt > priv->stats.maxpktcnt) - { - priv->stats.maxpktcnt = pktcnt; - } -#endif - /* Handle packet receipt */ - - enc_pktif(priv); - } - } - - /* RXERIF: The Receive Error Interrupt Flag (RXERIF) is used to - * indicate a receive buffer overflow condition. Alternately, this - * interrupt may indicate that too many packets are in the receive - * buffer and more cannot be stored without overflowing the EPKTCNT - * register. When a packet is being received and the receive buffer - * runs completely out of space, or EPKTCNT is 255 and cannot be - * incremented, the packet being received will be aborted (permanently - * lost) and the EIR.RXERIF bit will be set to 1. - * - * Once set, RXERIF can only be cleared by the host controller or by a - * Reset condition. Normally, upon the receive error condition, the - * host controller would process any packets pending from the receive - * buffer and then make additional room for future packets by - * advancing the ERXRDPT registers (low byte first) and decrementing - * the EPKTCNT register. - * - * Once processed, the host controller should use the BFC command to - * clear the EIR.RXERIF bit. - */ - - if ((eir & EIR_RXERIF) != 0) /* Receive Errror Interrupts */ - { - enc_rxerif(priv); /* Handle the RX error */ - enc_bfcgreg(priv, ENC_EIR, EIR_RXERIF); /* Clear the RXERIF interrupt */ - } - } - - /* Enable Ethernet interrupts */ - - enc_bfsgreg(priv, ENC_EIE, EIE_INTIE); - - /* Release lock on the SPI bus and uIP */ - - enc_unlock(priv); - uip_unlock(lock); - - /* Enable GPIO interrupts */ - - priv->lower->enable(priv->lower); -} - -/**************************************************************************** - * Function: enc_interrupt - * - * Description: - * Hardware interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_interrupt(int irq, FAR void *context) -{ - register FAR struct enc_driver_s *priv = &g_enc28j60[0]; - - /* In complex environments, we cannot do SPI transfers from the interrupt - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(work_available(&priv->irqwork)); - - /* Notice that further GPIO interrupts are disabled until the work is - * actually performed. This is to prevent overrun of the worker thread. - * Interrupts are re-enabled in enc_irqworker() when the work is completed. - */ - - priv->lower->disable(priv->lower); - return work_queue(HPWORK, &priv->irqwork, enc_irqworker, (FAR void *)priv, 0); -} - -/**************************************************************************** - * Function: enc_toworker - * - * Description: - * Our TX watchdog timed out. This is the worker thread continuation of - * the watchdog timer interrupt. Reset the hardware and start again. - * - * Parameters: - * arg - The reference to the driver structure (case to void*) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_toworker(FAR void *arg) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - uip_lock_t lock; - int ret; - - nlldbg("Tx timeout\n"); - DEBUGASSERT(priv); - - /* Get exclusive access to both uIP and the SPI bus. */ - - lock = uip_lock(); - enc_lock(priv); - - /* Increment statistics and dump debug info */ - -#ifdef CONFIG_ENC28J60_STATS - priv->stats.txtimeouts++; -#endif - - /* Then reset the hardware: Take the interface down, then bring it - * back up - */ - - ret = enc_ifdown(&priv->dev); - DEBUGASSERT(ret == OK); - ret = enc_ifup(&priv->dev); - DEBUGASSERT(ret == OK); - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&priv->dev, enc_uiptxpoll); - - /* Release lock on the SPI bus and uIP */ - - enc_unlock(priv); - uip_unlock(lock); -} - -/**************************************************************************** - * Function: enc_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Perform work on the worker thread. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_txtimeout(int argc, uint32_t arg, ...) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - int ret; - - /* In complex environments, we cannot do SPI transfers from the timout - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(priv && work_available(&priv->towork)); - - /* Notice that Tx timeout watchdog is not active so further Tx timeouts - * can occur until we restart the Tx timeout watchdog. - */ - - ret = work_queue(HPWORK, &priv->towork, enc_toworker, (FAR void *)priv, 0); - DEBUGASSERT(ret == OK); -} - -/**************************************************************************** - * Function: enc_pollworker - * - * Description: - * Periodic timer handler continuation. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_pollworker(FAR void *arg) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - uip_lock_t lock; - - DEBUGASSERT(priv); - - /* Get exclusive access to both uIP and the SPI bus. */ - - lock = uip_lock(); - enc_lock(priv); - - /* Verify that the hardware is ready to send another packet. The driver - * start a transmission process by setting ECON1.TXRTS. When the packet is - * finished transmitting or is aborted due to an error/cancellation, the - * ECON1.TXRTS bit will be cleared. - */ - - if ((enc_rdgreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0) - { - /* Yes.. update TCP timing states and poll uIP for new XMIT data. Hmmm.. - * looks like a bug here to me. Does this mean if there is a transmit - * in progress, we will missing TCP time state updates? - */ - - (void)uip_timer(&priv->dev, enc_uiptxpoll, ENC_POLLHSEC); - } - - /* Release lock on the SPI bus and uIP */ - - enc_unlock(priv); - uip_unlock(lock); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: enc_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_polltimer(int argc, uint32_t arg, ...) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - int ret; - - /* In complex environments, we cannot do SPI transfers from the timout - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(priv && work_available(&priv->pollwork)); - - /* Notice that poll watchdog is not active so further poll timeouts can - * occur until we restart the poll timeout watchdog. - */ - - ret = work_queue(HPWORK, &priv->pollwork, enc_pollworker, (FAR void *)priv, 0); - DEBUGASSERT(ret == OK); -} - -/**************************************************************************** - * Function: enc_ifup - * - * Description: - * NuttX Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_ifup(struct uip_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - int ret; - - nlldbg("Bringing up: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Initialize Ethernet interface, set the MAC address, and make sure that - * the ENC28J80 is not in power save mode. - */ - - ret = enc_reset(priv); - if (ret == OK) - { - enc_setmacaddr(priv); - enc_pwrfull(priv); - - /* Enable interrupts at the ENC28J60. Interrupts are still disabled - * at the interrupt controller. - */ - - enc_wrphy(priv, ENC_PHIE, PHIE_PGEIE | PHIE_PLNKIE); - enc_bfcgreg(priv, ENC_EIR, EIR_ALLINTS); - enc_wrgreg(priv, ENC_EIE, EIE_INTIE | EIE_PKTIE | EIE_LINKIE | - EIE_TXIE | EIE_TXERIE | EIE_RXERIE); - - /* Enable the receiver */ - - enc_bfsgreg(priv, ENC_ECON1, ECON1_RXEN); - - /* Set and activate a timer process */ - - (void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1, (uint32_t)priv); - - /* Mark the interface up and enable the Ethernet interrupt at the - * controller - */ - - priv->ifstate = ENCSTATE_UP; - priv->lower->enable(priv->lower); - } - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - return ret; -} - -/**************************************************************************** - * Function: enc_ifdown - * - * Description: - * NuttX Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_ifdown(struct uip_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - irqstate_t flags; - int ret; - - nlldbg("Taking down: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - priv->lower->disable(priv->lower); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(priv->txpoll); - wd_cancel(priv->txtimeout); - - /* Reset the device and leave in the power save state */ - - ret = enc_reset(priv); - enc_pwrsave(priv); - - priv->ifstate = ENCSTATE_DOWN; - irqrestore(flags); - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - return ret; -} - -/**************************************************************************** - * Function: enc_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int enc_txavail(struct uip_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - irqstate_t flags; - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Ignore the notification if the interface is not yet up */ - - flags = irqsave(); - if (priv->ifstate == ENCSTATE_UP) - { - /* Check if the hardware is ready to send another packet. The driver - * starts a transmission process by setting ECON1.TXRTS. When the packet is - * finished transmitting or is aborted due to an error/cancellation, the - * ECON1.TXRTS bit will be cleared. - */ - - if ((enc_rdgreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0) - { - /* The interface is up and TX is idle; poll uIP for new XMIT data */ - - (void)uip_poll(&priv->dev, enc_uiptxpoll); - } - } - - /* Un-lock the SPI bus */ - - irqrestore(flags); - enc_unlock(priv); - return OK; -} - -/**************************************************************************** - * Function: enc_addmac - * - * Description: - * NuttX Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int enc_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - return OK; -} -#endif - -/**************************************************************************** - * Function: enc_rmmac - * - * Description: - * NuttX Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int enc_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - return OK; -} -#endif - -/**************************************************************************** - * Function: enc_pwrsave - * - * Description: - * The ENC28J60 may be commanded to power-down via the SPI interface. - * When powered down, it will no longer be able to transmit and receive - * any packets. To maximize power savings: - * - * 1. Turn off packet reception by clearing ECON1.RXEN. - * 2. Wait for any in-progress packets to finish being received by - * polling ESTAT.RXBUSY. This bit should be clear before proceeding. - * 3. Wait for any current transmissions to end by confirming ECON1.TXRTS - * is clear. - * 4. Set ECON2.VRPS (if not already set). - * 5. Enter Sleep by setting ECON2.PWRSV. All MAC, MII and PHY registers - * become inaccessible as a result. Setting PWRSV also clears - * ESTAT.CLKRDY automatically. - * - * In Sleep mode, all registers and buffer memory will maintain their - * states. The ETH registers and buffer memory will still be accessible - * by the host controller. Additionally, the clock driver will continue - * to operate. The CLKOUT function will be unaffected. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_pwrsave(FAR struct enc_driver_s *priv) -{ - nllvdbg("Set PWRSV\n"); - - /* 1. Turn off packet reception by clearing ECON1.RXEN. */ - - enc_bfcgreg(priv, ENC_ECON1, ECON1_RXEN); - - /* 2. Wait for any in-progress packets to finish being received by - * polling ESTAT.RXBUSY. This bit should be clear before proceeding. - */ - - if (enc_waitbreg(priv, ENC_ESTAT, ESTAT_RXBUSY, 0) == OK) - { - /* 3. Wait for any current transmissions to end by confirming - * ECON1.TXRTS is clear. - */ - - enc_waitbreg(priv, ENC_ECON1, ECON1_TXRTS, 0); - - /* 4. Set ECON2.VRPS (if not already set). */ - /* enc_bfsgreg(priv, ENC_ECON2, ECON2_VRPS); <-- Set in enc_reset() */ - - /* 5. Enter Sleep by setting ECON2.PWRSV. */ - - enc_bfsgreg(priv, ENC_ECON2, ECON2_PWRSV); - } -} - -/**************************************************************************** - * Function: enc_pwrfull - * - * Description: - * When normal operation is desired, the host controller must perform - * a slightly modified procedure: - * - * 1. Wake-up by clearing ECON2.PWRSV. - * 2. Wait at least 300 ìs for the PHY to stabilize. To accomplish the - * delay, the host controller may poll ESTAT.CLKRDY and wait for it - * to become set. - * 3. Restore receive capability by setting ECON1.RXEN. - * - * After leaving Sleep mode, there is a delay of many milliseconds - * before a new link is established (assuming an appropriate link - * partner is present). The host controller may wish to wait until - * the link is established before attempting to transmit any packets. - * The link status can be determined by polling the PHSTAT2.LSTAT bit. - * Alternatively, the link change interrupt may be used if it is - * enabled. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_pwrfull(FAR struct enc_driver_s *priv) -{ - nllvdbg("Clear PWRSV\n"); - - /* 1. Wake-up by clearing ECON2.PWRSV. */ - - enc_bfcgreg(priv, ENC_ECON2, ECON2_PWRSV); - - /* 2. Wait at least 300 ìs for the PHY to stabilize. To accomplish the - * delay, the host controller may poll ESTAT.CLKRDY and wait for it to - * become set. - */ - - enc_waitbreg(priv, ENC_ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY); - - /* 3. Restore receive capability by setting ECON1.RXEN. - * - * The caller will do this when it is read to receive packets - */ -} - -/**************************************************************************** - * Function: enc_setmacaddr - * - * Description: - * Set the MAC address to the configured value. This is done after ifup - * or after a TX timeout. Note that this means that the interface must - * be down before configuring the MAC addr. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_setmacaddr(FAR struct enc_driver_s *priv) -{ - /* Program the hardware with it's MAC address (for filtering). - * MAADR1 MAC Address Byte 1 (MAADR<47:40>), OUI Byte 1 - * MAADR2 MAC Address Byte 2 (MAADR<39:32>), OUI Byte 2 - * MAADR3 MAC Address Byte 3 (MAADR<31:24>), OUI Byte 3 - * MAADR4 MAC Address Byte 4 (MAADR<23:16>) - * MAADR5 MAC Address Byte 5 (MAADR<15:8>) - * MAADR6 MAC Address Byte 6 (MAADR<7:0>) - */ - - enc_wrbreg(priv, ENC_MAADR1, priv->dev.d_mac.ether_addr_octet[0]); - enc_wrbreg(priv, ENC_MAADR2, priv->dev.d_mac.ether_addr_octet[1]); - enc_wrbreg(priv, ENC_MAADR3, priv->dev.d_mac.ether_addr_octet[2]); - enc_wrbreg(priv, ENC_MAADR4, priv->dev.d_mac.ether_addr_octet[3]); - enc_wrbreg(priv, ENC_MAADR5, priv->dev.d_mac.ether_addr_octet[4]); - enc_wrbreg(priv, ENC_MAADR6, priv->dev.d_mac.ether_addr_octet[5]); -} - -/**************************************************************************** - * Function: enc_reset - * - * Description: - * Stop, reset, re-initialize, and restart the ENC28J60. This is done - * initially, on ifup, and after a TX timeout. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_reset(FAR struct enc_driver_s *priv) -{ - uint8_t regval; - - nlldbg("Reset\n"); - - /* Configure SPI for the ENC28J60 */ - - enc_configspi(priv->spi); - - /* Reset the ENC28J60 */ - - enc_src(priv); - - /* Initialize ECON1: Clear ECON1 */ - - enc_wrgreg(priv, ENC_ECON1, 0x00); - - /* Initialize ECON2: Enable address auto increment and voltage - * regulator powersave. - */ - - enc_wrgreg(priv, ENC_ECON2, ECON2_AUTOINC | ECON2_VRPS); - - /* Initialize receive buffer. - * First, set the receive buffer start address. - */ - - priv->nextpkt = PKTMEM_RX_START; - enc_wrbreg(priv, ENC_ERXSTL, PKTMEM_RX_START & 0xff); - enc_wrbreg(priv, ENC_ERXSTH, PKTMEM_RX_START >> 8); - - /* Set the receive data pointer */ - - enc_wrbreg(priv, ENC_ERXRDPTL, PKTMEM_RX_START & 0xff); - enc_wrbreg(priv, ENC_ERXRDPTH, PKTMEM_RX_START >> 8); - - /* Set the receive buffer end. */ - - enc_wrbreg(priv, ENC_ERXNDL, PKTMEM_RX_END & 0xff); - enc_wrbreg(priv, ENC_ERXNDH, PKTMEM_RX_END >> 8); - - /* Set transmit buffer start. */ - - enc_wrbreg(priv, ENC_ETXSTL, PKTMEM_TX_START & 0xff); - enc_wrbreg(priv, ENC_ETXSTH, PKTMEM_TX_START >> 8); - - /* Check if we are actually communicating with the ENC28J60. If its - * 0x00 or 0xff, then we are probably not communicating correctly - * via SPI. - */ - - regval = enc_rdbreg(priv, ENC_EREVID); - if (regval == 0x00 || regval == 0xff) - { - nlldbg("Bad Rev ID: %02x\n", regval); - return -ENODEV; - } - - nllvdbg("Rev ID: %02x\n", regval); - - /* Set filter mode: unicast OR broadcast AND crc valid */ - - enc_wrbreg(priv, ENC_ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN); - - /* Enable MAC receive */ - - enc_wrbreg(priv, ENC_MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); - - /* Enable automatic padding and CRC operations */ - -#ifdef CONFIG_ENC28J60_HALFDUPLEX - enc_wrbreg(priv, ENC_MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN); - enc_wrbreg(priv, ENC_MACON4, MACON4_DEFER); /* Defer transmission enable */ - - /* Set Non-Back-to-Back Inter-Packet Gap */ - - enc_wrbreg(priv, ENC_MAIPGL, 0x12); - enc_wrbreg(priv, ENC_MAIPGH, 0x0c); - - /* Set Back-to-Back Inter-Packet Gap */ - - enc_wrbreg(priv, ENC_MABBIPG, 0x12); -#else - /* Set filter mode: unicast OR broadcast AND crc valid AND Full Duplex */ - - enc_wrbreg(priv, ENC_MACON3, - MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX); - - /* Set Non-Back-to-Back Inter-Packet Gap */ - - enc_wrbreg(priv, ENC_MAIPGL, 0x12); - - /* Set Back-to-Back Inter-Packet Gap */ - - enc_wrbreg(priv, ENC_MABBIPG, 0x15); -#endif - - /* Set the maximum packet size which the controller will accept */ - - enc_wrbreg(priv, ENC_MAMXFLL, CONFIG_NET_BUFSIZE & 0xff); - enc_wrbreg(priv, ENC_MAMXFLH, CONFIG_NET_BUFSIZE >> 8); - - /* Configure LEDs (No, just use the defaults for now) */ - /* enc_wrphy(priv, ENC_PHLCON, ??); */ - - /* Setup up PHCON1 & 2 */ - -#ifdef CONFIG_ENC28J60_HALFDUPLEX - enc_wrphy(priv, ENC_PHCON1, 0x00); - enc_wrphy(priv, ENC_PHCON2, PHCON2_HDLDIS); -#else - enc_wrphy(priv, ENC_PHCON1, PHCON1_PDPXMD); - enc_wrphy(priv, ENC_PHCON2, 0x00); -#endif - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: enc_initialize - * - * Description: - * Initialize the Ethernet driver. The ENC28J60 device is assumed to be - * in the post-reset state upon entry to this function. - * - * Parameters: - * spi - A reference to the platform's SPI driver for the ENC28J60 - * lower - The MCU-specific interrupt used to control low-level MCU - * functions (i.e., ENC28J60 GPIO interrupts). - * devno - If more than one ENC28J60 is supported, then this is the - * zero based number that identifies the ENC28J60; - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -int enc_initialize(FAR struct spi_dev_s *spi, - FAR const struct enc_lower_s *lower, unsigned int devno) -{ - FAR struct enc_driver_s *priv; - - DEBUGASSERT(devno < CONFIG_ENC28J60_NINTERFACES); - priv = &g_enc28j60[devno]; - - /* Initialize the driver structure */ - - memset(g_enc28j60, 0, CONFIG_ENC28J60_NINTERFACES*sizeof(struct enc_driver_s)); - priv->dev.d_ifup = enc_ifup; /* I/F down callback */ - priv->dev.d_ifdown = enc_ifdown; /* I/F up (new IP address) callback */ - priv->dev.d_txavail = enc_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - priv->dev.d_addmac = enc_addmac; /* Add multicast MAC address */ - priv->dev.d_rmmac = enc_rmmac; /* Remove multicast MAC address */ -#endif - priv->dev.d_private = priv; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - priv->txpoll = wd_create(); /* Create periodic poll timer */ - priv->txtimeout = wd_create(); /* Create TX timeout timer */ - priv->spi = spi; /* Save the SPI instance */ - priv->lower = lower; /* Save the low-level MCU interface */ - - /* The interface should be in the down state. However, this function is called - * too early in initalization to perform the ENC28J60 reset in enc_ifdown. We - * are depending upon the fact that the application level logic will call enc_ifdown - * later to reset the ENC28J60. NOTE: The MAC address will not be set up until - * enc_ifup() is called. That gives the app time to set the MAC address before - * bringing the interface up. - */ - - priv->ifstate = ENCSTATE_UNINIT; - - /* Attach the interrupt to the driver (but don't enable it yet) */ - - if (lower->attach(lower, enc_interrupt)) - { - /* We could not attach the ISR to the interrupt */ - - return -EAGAIN; - } - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - return netdev_register(&priv->dev); -} - -/**************************************************************************** - * Function: enc_stats - * - * Description: - * Return accumulated ENC28J60 statistics. Statistics are cleared after - * being returned. - * - * Parameters: - * devno - If more than one ENC28J60 is supported, then this is the - * zero based number that identifies the ENC28J60; - * stats - The user-provided location to return the statistics. - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_ENC28J60_STATS -int enc_stats(unsigned int devno, struct enc_stats_s *stats) -{ - FAR struct enc_driver_s *priv ; - irqstate_t flags; - - DEBUGASSERT(devno < CONFIG_ENC28J60_NINTERFACES); - priv = &g_enc28j60[devno]; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - memcpy(stats, &priv->stats, sizeof(struct enc_stats_s)); - memset(&priv->stats, 0, sizeof(struct enc_stats_s)); - irqrestore(flags); - return OK; -} -#endif -#endif /* CONFIG_NET && CONFIG_ENC28J60_NET */ - diff --git a/nuttx/drivers/net/enc28j60.h b/nuttx/drivers/net/enc28j60.h deleted file mode 100644 index 6a0553a95..000000000 --- a/nuttx/drivers/net/enc28j60.h +++ /dev/null @@ -1,477 +0,0 @@ -/**************************************************************************** - * drivers/net/enc28j60.h - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: - * - ENC28J60 Data Sheet, Stand-Alone Ethernet Controller with SPI Interface, - * DS39662C, 2008 Microchip Technology Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_NET_ENC28J60_H -#define __DRIVERS_NET_ENC28J60_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* ENC28J60 Commands ********************************************************/ -/* A total of seven instructions are implemented on the ENC28J60. Where: - * - * aaaaaa is the 5-bit address of a control register, and - * dddddddd is one or more bytes of data that may accompany the command. - */ - -#define ENC_RCR (0x00) /* Read Control Register - * 000 | aaaaa | (Register value returned)) */ -#define ENC_RBM (0x3a) /* Read Buffer Memory - * 001 | 11010 | (Read buffer data follows) */ -#define ENC_WCR (0x40) /* Write Control Register - * 010 | aaaaa | dddddddd */ -#define ENC_WBM (0x7a) /* Write Buffer Memory - * 011 | 11010 | (Write buffer data follows) */ -#define ENC_BFS (0x80) /* Bit Field Set - * 100 | aaaaa | dddddddd */ -#define ENC_BFC (0xa0) /* Bit Field Clear - * 101 | aaaaa | dddddddd */ -#define ENC_SRC (0xff) /* System Reset - * 111 | 11111 | (No data) */ - -/* Global Control Registers *************************************************/ -/* Control registers are accessed with the RCR, RBM, WCR, BFS, and BFC - * commands. The following identifies all ENC28J60 control registers. The - * control register memory is partitioned into four banks, selectable by the - * bank select bits, BSEL1:BSEL0, in the ECON1 register. - * - * The last five locations (0x1b to 0x1f) of all banks point to a common set - * of registers: EIE, EIR, ESTAT, ECON2 and ECON1. These are key registers - * used in controlling and monitoring the operation of the device. Their - * common mapping allows easy access without switching the bank. - * - * Control registers for the ENC28J60 are generically grouped as ETH, MAC and - * MII registers. Register names starting with E belong to the ETH group. - * Similarly, registers names starting with MA belong to the MAC group and - * registers prefixed with MI belong to the MII group. - */ - -#define ENC_EIE (0x1b) /* Ethernet Interrupt Enable Register */ -#define ENC_EIR (0x1c) /* Ethernet Interupt Request Register */ -#define ENC_ESTAT (0x1d) /* Ethernet Status Register */ -#define ENC_ECON2 (0x1e) /* Ethernet Control 2 Register */ -#define ENC_ECON1 (0x1f) /* Ethernet Control 1 Register */ - -/* Ethernet Interrupt Enable Register Bit Definitions */ - -#define EIE_RXERIE (1 << 0) /* Bit 0: Receive Error Interrupt Enable */ -#define EIE_TXERIE (1 << 1) /* Bit 1: Transmit Error Interrupt Enable */ - /* Bit 2: Reserved */ -#define EIE_TXIE (1 << 3) /* Bit 3: Transmit Enable */ -#define EIE_LINKIE (1 << 4) /* Bit 4: Link Status Change Interrupt Enable */ -#define EIE_DMAIE (1 << 5) /* Bit 5: DMA Interrupt Enable */ -#define EIE_PKTIE (1 << 6) /* Bit 6: Receive Packet Pending Interrupt Enable */ -#define EIE_INTIE (1 << 7) /* Bit 7: Global INT Interrupt Enable */ - -/* Ethernet Interrupt Request Register Bit Definitions */ - -#define EIR_RXERIF (1 << 0) /* Bit 0: Receive Error Interrupt */ -#define EIR_TXERIF (1 << 1) /* Bit 1: Transmit Error Interrupt */ - /* Bit 2: Reserved */ -#define EIR_TXIF (1 << 3) /* Bit 3: Transmit Interrupt */ -#define EIR_LINKIF (1 << 4) /* Bit 4: Link Change Interrupt */ -#define EIR_DMAIF (1 << 5) /* Bit 5: DMA Interrupt */ -#define EIR_PKTIF (1 << 6) /* Bit 6: Receive Packet Pending Interrupt */ - /* Bit 7: Reserved */ -#define EIR_ALLINTS (0x7b) /* All interrupts */ - -/* Ethernet Status Register Bit Definitions */ - -#define ESTAT_CLKRDY (1 << 0) /* Bit 0: Clock Ready */ -#define ESTAT_TXABRT (1 << 1) /* Bit 1: Transmit Abort Error */ -#define ESTAT_RXBUSY (1 << 2) /* Bit 2: Receive Busy */ - /* Bit 3: Reserved */ -#define ESTAT_LATECOL (1 << 4) /* Bit 4: Late Collision Error */ - /* Bit 5: Reserved */ -#define ESTAT_BUFER (1 << 6) /* Bit 6: Ethernet Buffer Error Status */ -#define ESTAT_INT (1 << 7) /* Bit 7: INT Interrupt */ - -/* Ethernet Control 1 Register Bit Definitions */ - -#define ECON1_BSEL_SHIFT (0) /* Bits 0-1: Bank select */ -#define ECON1_BSEL_MASK (3 << ECON1_BSEL_SHIFT) -# define ECON1_BSEL_BANK0 (0 << ECON1_BSEL_SHIFT) /* Bank 0 */ -# define ECON1_BSEL_BANK1 (1 << ECON1_BSEL_SHIFT) /* Bank 1 */ -# define ECON1_BSEL_BANK2 (2 << ECON1_BSEL_SHIFT) /* Bank 2 */ -# define ECON1_BSEL_BANK3 (3 << ECON1_BSEL_SHIFT) /* Bank 3 */ -#define ECON1_RXEN (1 << 2) /* Bit 2: Receive Enable */ -#define ECON1_TXRTS (1 << 3) /* Bit 3: Transmit Request to Send */ -#define ECON1_CSUMEN (1 << 4) /* Bit 4: DMA Checksum Enable */ -#define ECON1_DMAST (1 << 5) /* Bit 5: DMA Start and Busy Status */ -#define ECON1_RXRST (1 << 6) /* Bit 6: Receive Logic Reset */ -#define ECON1_TXRST (1 << 7) /* Bit 7: Transmit Logic Reset */ - -/* Ethernet Control 2 Register */ - /* Bits 0-2: Reserved */ -#define ECON2_VRPS (1 << 3) /* Bit 3: Voltage Regulator Power Save Enable */ - /* Bit 4: Reserved */ -#define ECON2_PWRSV (1 << 5) /* Bit 5: Power Save Enable */ -#define ECON2_PKTDEC (1 << 6) /* Bit 6: Packet Decrement */ -#define ECON2_AUTOINC (1 << 7) /* Bit 7: Automatic Buffer Pointer Increment Enable */ - -/* Banked Control Registers *************************************************/ -/* The remaining control registers are identified with a a 5 bit address and - * a bank selection. We pack the bank number and an indication if this is - * a MAC/PHY register access together with the control register address - * together to keep the design simpler. - */ - -#define ENC_ADDR_SHIFT (0) /* Bits 0-4: Register address */ -#define ENC_ADDR_MASK (0x1f << ENC_ADDR_SHIFT) -#define ENC_BANK_SHIFT (5) /* Bits 5-6: Bank number */ -#define ENC_BANK_MASK (3 << ENC_BSEL_SHIFT) -# define ENC_BANK0 (0 << ENC_BSEL_SHIFT) -# define ENC_BANK1 (1 << ENC_BSEL_SHIFT) -# define ENC_BANK2 (2 << ENC_BSEL_SHIFT) -# define ENC_BANK3 (3 << ENC_BSEL_SHIFT) -#define ENC_PHYMAC_SHIFT (7) /* Bit 7: This is a PHY/MAC command */ -#define ENC_PHYMAC (1 << ENC_PHYMAC_SHIFT) - -#define REGADDR(a,b,m) ((m) << ENC_PHYMAC_SHIFT | (b) << ENC_BANK_SHIFT | (a)) -#define GETADDR(a) ((a) & ENC_ADDR_MASK) -#define GETBANK(a) (((a) >> ENC_BANK_SHIFT) & 3) -#define ISPHYMAC(a) (((a) & ENC_PHYMAC) != 0) - -/* Bank 0 Control Register Addresses */ - -#define ENC_ERDPTL REGADDR(0x00, 0, 0) /* Read Pointer Low Byte (ERDPT<7:0> */ -#define ENC_ERDPTH REGADDR(0x01, 0, 0) /* Read Pointer High Byte (ERDPT<12:8>) */ -#define ENC_EWRPTL REGADDR(0x02, 0, 0) /* Write Pointer Low Byte (EWRPT<7:0>) */ -#define ENC_EWRPTH REGADDR(0x03, 0, 0) /* Write Pointer High Byte (EWRPT<12:8>) */ -#define ENC_ETXSTL REGADDR(0x04, 0, 0) /* TX Start Low Byte (ETXST<7:0>) */ -#define ENC_ETXSTH REGADDR(0x05, 0, 0) /* TX Start High Byte (ETXST<12:8>) */ -#define ENC_ETXNDL REGADDR(0x06, 0, 0) /* TX End Low Byte (ETXND<7:0>) */ -#define ENC_ETXNDH REGADDR(0x07, 0, 0) /* TX End High Byte (ETXND<12:8>) */ -#define ENC_ERXSTL REGADDR(0x08, 0, 0) /* RX Start Low Byte (ERXST<7:0>) */ -#define ENC_ERXSTH REGADDR(0x09, 0, 0) /* RX Start High Byte (ERXST<12:8>) */ -#define ENC_ERXNDL REGADDR(0x0a, 0, 0) /* RX End Low Byte (ERXND<7:0>) */ -#define ENC_ERXNDH REGADDR(0x0b, 0, 0) /* RX End High Byte (ERXND<12:8>) */ -#define ENC_ERXRDPTL REGADDR(0x0c, 0, 0) /* RX RD Pointer Low Byte (ERXRDPT<7:0>) */ -#define ENC_ERXRDPTH REGADDR(0x0d, 0, 0) /* RX RD Pointer High Byte (ERXRDPT<12:8>) */ -#define ENC_ERXWRPTL REGADDR(0x0e, 0, 0) /* RX WR Pointer Low Byte (ERXWRPT<7:0>) */ -#define ENC_ERXWRPTH REGADDR(0x0f, 0, 0) /* RX WR Pointer High Byte (ERXWRPT<12:8>) */ -#define ENC_EDMASTL REGADDR(0x10, 0, 0) /* DMA Start Low Byte (EDMAST<7:0>) */ -#define ENC_EDMASTH REGADDR(0x11, 0, 0) /* DMA Start High Byte (EDMAST<12:8>) */ -#define ENC_EDMANDL REGADDR(0x12, 0, 0) /* DMA End Low Byte (EDMAND<7:0>) */ -#define ENC_EDMANDH REGADDR(0x13, 0, 0) /* DMA End High Byte (EDMAND<12:8>) */ -#define ENC_EDMADSTL REGADDR(0x14, 0, 0) /* DMA Destination Low Byte (EDMADST<7:0>) */ -#define ENC_EDMADSTH REGADDR(0x15, 0, 0) /* DMA Destination High Byte (EDMADST<12:8>) */ -#define ENC_EDMACSL REGADDR(0x16, 0, 0) /* DMA Checksum Low Byte (EDMACS<7:0>) */ -#define ENC_EDMACSH REGADDR(0x17, 0, 0) /* DMA Checksum High Byte (EDMACS<15:8>) */ - /* 0x18-0x1a: Reserved */ - /* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */ -/* Bank 1 Control Register Addresses */ - -#define ENC_EHT0 REGADDR(0x00, 1, 0) /* Hash Table Byte 0 (EHT<7:0>) */ -#define ENC_EHT1 REGADDR(0x01, 1, 0) /* Hash Table Byte 1 (EHT<15:8>) */ -#define ENC_EHT2 REGADDR(0x02, 1, 0) /* Hash Table Byte 2 (EHT<23:16>) */ -#define ENC_EHT3 REGADDR(0x03, 1, 0) /* Hash Table Byte 3 (EHT<31:24>) */ -#define ENC_EHT4 REGADDR(0x04, 1, 0) /* Hash Table Byte 4 (EHT<39:32>) */ -#define ENC_EHT5 REGADDR(0x05, 1, 0) /* Hash Table Byte 5 (EHT<47:40>) */ -#define ENC_EHT6 REGADDR(0x06, 1, 0) /* Hash Table Byte 6 (EHT<55:48>) */ -#define ENC_EHT7 REGADDR(0x07, 1, 0) /* Hash Table Byte 7 (EHT<63:56>) */ -#define ENC_EPMM0 REGADDR(0x08, 1, 0) /* Pattern Match Mask Byte 0 (EPMM<7:0>) */ -#define ENC_EPMM1 REGADDR(0x09, 1, 0) /* Pattern Match Mask Byte 1 (EPMM<15:8>) */ -#define ENC_EPMM2 REGADDR(0x0a, 1, 0) /* Pattern Match Mask Byte 2 (EPMM<23:16>) */ -#define ENC_EPMM3 REGADDR(0x0b, 1, 0) /* Pattern Match Mask Byte 3 (EPMM<31:24>) */ -#define ENC_EPMM4 REGADDR(0x0c, 1, 0) /* Pattern Match Mask Byte 4 (EPMM<39:32>) */ -#define ENC_EPMM5 REGADDR(0x0d, 1, 0) /* Pattern Match Mask Byte 5 (EPMM<47:40>) */ -#define ENC_EPMM6 REGADDR(0x0e, 1, 0) /* Pattern Match Mask Byte 6 (EPMM<55:48>) */ -#define ENC_EPMM7 REGADDR(0x0f, 1, 0) /* Pattern Match Mask Byte 7 (EPMM<63:56>) */ -#define ENC_EPMCSL REGADDR(0x10, 1, 0) /* Pattern Match Checksum Low Byte (EPMCS<7:0>) */ -#define ENC_EPMCSH REGADDR(0x11, 1, 0) /* Pattern Match Checksum High Byte (EPMCS<15:0>) */ - /* 0x12-0x13: Reserved */ -#define ENC_EPMOL REGADDR(0x14, 1, 0) /* Pattern Match Offset Low Byte (EPMO<7:0>) */ -#define ENC_EPMOH REGADDR(0x15, 1, 0) /* Pattern Match Offset High Byte (EPMO<12:8>) */ - /* 0x16-0x17: Reserved */ -#define ENC_ERXFCON REGADDR(0x18, 1, 0) /* Receive Filter Configuration */ -#define ENC_EPKTCNT REGADDR(0x19, 1, 0) /* Ethernet Packet Count */ - /* 0x1a: Reserved */ - /* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */ - -/* Receive Filter Configuration Bit Definitions */ - -#define ERXFCON_BCEN (1 << 0) /* Bit 0: Broadcast Filter Enable */ -#define ERXFCON_MCEN (1 << 1) /* Bit 1: Multicast Filter Enable */ -#define ERXFCON_HTEN (1 << 2) /* Bit 2: Hash Table Filter Enable */ -#define ERXFCON_MPEN (1 << 3) /* Bit 3: Magic Packet Filter Enable */ -#define ERXFCON_PMEN (1 << 4) /* Bit 4: Pattern Match Filter Enable */ -#define ERXFCON_CRCEN (1 << 5) /* Bit 5: Post-Filter CRC Check Enable */ -#define ERXFCON_ANDOR (1 << 6) /* Bit 6: AND/OR Filter Select */ -#define ERXFCON_UCEN (1 << 7) /* Bit 7: Unicast Filter Enable */ - -/* Bank 2 Control Register Addresses */ - -#define ENC_MACON1 REGADDR(0x00, 2, 1) /* MAC Control 1 */ - /* 0x01: Reserved */ -#define ENC_MACON3 REGADDR(0x02, 2, 1) /* MAC Control 3 */ -#define ENC_MACON4 REGADDR(0x03, 2, 1) /* MAC Control 4 */ -#define ENC_MABBIPG REGADDR(0x04, 2, 1) /* Back-to-Back Inter-Packet Gap (BBIPG<6:0>) */ - /* 0x05: Reserved */ -#define ENC_MAIPGL REGADDR(0x06, 2, 1) /* Non-Back-to-Back Inter-Packet Gap Low Byte (MAIPGL<6:0>) */ -#define ENC_MAIPGH REGADDR(0x07, 2, 1) /* Non-Back-to-Back Inter-Packet Gap High Byte (MAIPGH<6:0>) */ -#define ENC_MACLCON1 REGADDR(0x08, 2, 1) /* MAC Collision Control 1 */ -#define ENC_MACLCON2 REGADDR(0x09, 2, 1) /* MAC Collision Control 2 */ -#define ENC_MAMXFLL REGADDR(0x0a, 2, 1) /* Maximum Frame Length Low Byte (MAMXFL<7:0>) */ -#define ENC_MAMXFLH REGADDR(0x0b, 2, 1) /* Maximum Frame Length High Byte (MAMXFL<15:8>) */ - /* 0x0c-0x11: Reserved */ -#define ENC_MICMD REGADDR(0x12, 2, 1) /* MII Command Register */ - /* 0x13: Reserved */ -#define ENC_MIREGADR REGADDR(0x14, 2, 1) /* MII Register Address */ - /* 0x15: Reserved */ -#define ENC_MIWRL REGADDR(0x16, 2, 1) /* MII Write Data Low Byte (MIWR<7:0>) */ -#define ENC_MIWRH REGADDR(0x17, 2, 1) /* MII Write Data High Byte (MIWR<15:8>) */ -#define ENC_MIRDL REGADDR(0x18, 2, 1) /* MII Read Data Low Byte (MIRD<7:0>) */ -#define ENC_MIRDH REGADDR(0x19, 2, 1) /* MII Read Data High Byte(MIRD<15:8>) */ - /* 0x1a: Reserved */ - /* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */ - -/* MAC Control 1 Register Bit Definitions */ - -#define MACON1_MARXEN (1 << 0) /* Bit 0: MAC Receive Enable */ -#define MACON1_PASSALL (1 << 1) /* Bit 1: Pass All Received Frames Enable */ -#define MACON1_RXPAUS (1 << 2) /* Bit 2: Pause Control Frame Reception Enable */ -#define MACON1_TXPAUS (1 << 3) /* Bit 3: Pause Control Frame Transmission Enable */ - /* Bits 4-7: Unimplemented or reserved */ - -/* MAC Control 1 Register Bit Definitions */ - -#define MACON3_FULDPX (1 << 0) /* Bit 0: MAC Full-Duplex Enable */ -#define MACON3_FRMLNEN (1 << 1) /* Bit 1: Frame Length Checking Enable */ -#define MACON3_HFRMLEN (1 << 2) /* Bit 2: Huge Frame Enable */ -#define MACON3_PHDRLEN (1 << 3) /* Bit 3: Proprietary Header Enable */ -#define MACON3_TXCRCEN (1 << 4) /* Bit 4: Transmit CRC Enable */ -#define MACON3_PADCFG0 (1 << 5) /* Bit 5: Automatic Pad and CRC Configuration */ -#define MACON3_PADCFG1 (1 << 6) /* Bit 6: " " " " " " " " " " */ -#define MACON3_PADCFG2 (1 << 7) /* Bit 7: " " " " " " " " " " */ - -/* MAC Control 1 Register Bit Definitions */ - -#define MACON4_NOBKOFF (1 << 4) /* Bit 4: No Backoff Enable */ -#define MACON4_BPEN (1 << 5) /* Bit 5: No Backoff During Backpressure Enable */ -#define MACON4_DEFER (1 << 6) /* Bit 6: Defer Transmission Enable bit */ - -/* MII Command Register Bit Definitions */ - -#define MICMD_MIIRD (1 << 0) /* Bit 0: MII Read Enable */ -#define MICMD_MIISCAN (1 << 1) /* Bit 1: MII Scan Enable */ - -/* Bank 3 Control Register Addresses */ - -#define ENC_MAADR5 REGADDR(0x00, 3, 1) /* MAC Address Byte 5 (MAADR<15:8>) */ -#define ENC_MAADR6 REGADDR(0x01, 3, 1) /* MAC Address Byte 6 (MAADR<7:0>) */ -#define ENC_MAADR3 REGADDR(0x02, 3, 1) /* MAC Address Byte 3 (MAADR<31:24>), OUI Byte 3 */ -#define ENC_MAADR4 REGADDR(0x03, 3, 1) /* MAC Address Byte 4 (MAADR<23:16>) */ -#define ENC_MAADR1 REGADDR(0x04, 3, 1) /* MAC Address Byte 1 (MAADR<47:40>), OUI Byte 1 */ -#define ENC_MAADR2 REGADDR(0x05, 3, 1) /* MAC Address Byte 2 (MAADR<39:32>), OUI Byte 2 */ -#define ENC_EBSTSD REGADDR(0x06, 3, 0) /* Built-in Self-Test Fill Seed (EBSTSD<7:0>) */ -#define ENC_EBSTCON REGADDR(0x07, 3, 0) /* Built-in Self-Test Control */ -#define ENC_EBSTCSL REGADDR(0x08, 3, 0) /* Built-in Self-Test Checksum Low Byte (EBSTCS<7:0>) */ -#define ENC_EBSTCSH REGADDR(0x09, 3, 0) /* Built-in Self-Test Checksum High Byte (EBSTCS<15:8>) */ -#define ENC_MISTAT REGADDR(0x0a, 3, 1) /* MII Status Register */ - /* 0x0b-0x11: Reserved */ -#define ENC_EREVID REGADDR(0x12, 3, 0) /* Ethernet Revision ID */ - /* 0x13-0x14: Reserved */ -#define ENC_ECOCON REGADDR(0x15, 3, 0) /* Clock Output Control */ - /* 0x16: Reserved */ -#define ENC_EFLOCON REGADDR(0x17, 3, 0) /* Ethernet Flow Control */ -#define ENC_EPAUSL REGADDR(0x18, 3, 0) /* Pause Timer Value Low Byte (EPAUS<7:0>) */ -#define ENC_EPAUSH REGADDR(0x19, 3, 0) /* Pause Timer Value High Byte (EPAUS<15:8>) */ - /* 0x1a: Reserved */ - /* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */ - -/* Built-in Self-Test Control Register Bit Definitions */ - -#define EBSTCON_BISTST (1 << 0) /* Bit 0: Built-in Self-Test Start/Busy */ -#define EBSTCON_TME (1 << 1) /* Bit 1: Test Mode Enable */ -#define EBSTCON_TMSEL0 (1 << 2) /* Bit 2: Test Mode Select */ -#define EBSTCON_TMSEL1 (1 << 3) /* Bit 3: " " " " " " */ -#define EBSTCON_PSEL (1 << 4) /* Bit 4: Port Select */ -#define EBSTCON_PSV0 (1 << 5) /* Bit 5: Pattern Shift Value */ -#define EBSTCON_PSV1 (1 << 6) /* Bit 6: " " " " " */ -#define EBSTCON_PSV2 (1 << 7) /* Bit 7: " " " " " */ - -/* MII Status Register Register Bit Definitions */ - -#define MISTAT_BUSY (1 << 0) /* Bit 0: MII Management Busy */ -#define MISTAT_SCAN (1 << 1) /* Bit 1: MII Management Scan Operation */ -#define MISTAT_NVALID (1 << 2) /* Bit 2: MII Management Read Data Not Valid */ - /* Bits 3-7: Reserved or unimplemented */ - -/* Ethernet Flow Control Register Bit Definitions */ - -#define EFLOCON_FCEN0 (1 << 0) /* Bit 0: Flow Control Enable */ -#define EFLOCON_FCEN1 (1 << 1) /* Bit 1: " " " " " " */ -#define EFLOCON_FULDPXS (1 << 2) /* Bit 2: Read-Only MAC Full-Duplex Shadow */ - /* Bits 3-7: Reserved or unimplemented */ - -/* PHY Registers ************************************************************/ - -#define ENC_PHCON1 (0x00) /* PHY Control Register 1 */ -#define ENC_PHSTAT1 (0x01) /* PHY Status 1 */ -#define ENC_PHID1 (0x02) /* PHY ID Register 1 */ -#define ENC_PHID2 (0x03) /* PHY ID Register 2 */ -#define ENC_PHCON2 (0x10) /* PHY Control Register 2 */ -#define ENC_PHSTAT2 (0x11) /* PHY Status 2 */ -#define ENC_PHIE (0x12) /* PHY Interrupt Enable Register */ -#define ENC_PHIR (0x13) /* PHY Interrupt Request Register */ -#define ENC_PHLCON (0x14) - -/* PHY Control Register 1 Register Bit Definitions */ - -#define PHCON1_PDPXMD (1 << 8) /* Bit 8: PHY Duplex Mode */ -#define PHCON1_PPWRSV (1 << 11) /* Bit 11: PHY Power-Down */ -#define PHCON1_PLOOPBK (1 << 14) /* Bit 14: PHY Loopback */ -#define PHCON1_PRST (1 << 15) /* Bit 15: PHY Software Reset */ - -/* PHY Status 1 Register Bit Definitions */ - -#define PHSTAT1_JBSTAT (1 << 1) /* Bit 1: PHY Latching Jabber Status */ -#define PHSTAT1_LLSTAT (1 << 2) /* Bit 2: PHY Latching Link Status */ -#define PHSTAT1_PHDPX (1 << 11) /* Bit 11: PHY Half-Duplex Capable */ -#define PHSTAT1_PFDPX (1 << 12) /* Bit 12: PHY Full-Duplex Capable */ - -/* PHY Control Register 2 Register Bit Definitions */ - -#define PHCON2_HDLDIS (1 << 8) /* Bit 8: PHY Half-Duplex Loopback Disable */ -#define PHCON2_JABBER (1 << 10) /* Bit 10: Jabber Correction Disable */ -#define PHCON2_TXDIS (1 << 13) /* Bit 13: Twisted-Pair Transmitter Disable */ -#define PHCON2_FRCLINK (1 << 14) /* Bit 14: PHY Force Linkup */ - -/* PHY Status 2 Register Bit Definitions */ - -#define PHSTAT2_PLRITY (1 << 5) /* Bit 5: Polarity Status */ -#define PHSTAT2_DPXSTAT (1 << 9) /* Bit 9: PHY Duplex Status */ -#define PHSTAT2_LSTAT (1 << 10) /* Bit 10: PHY Link Status */ -#define PHSTAT2_COLSTAT (1 << 11) /* Bit 11: PHY Collision Status */ -#define PHSTAT2_RXSTAT (1 << 12) /* Bit 12: PHY Receive Status */ -#define PHSTAT2_TXSTAT (1 << 13) /* Bit 13: PHY Transmit Status */ - -/* PHY Interrupt Enable Register Bit Definitions */ - -#define PHIE_PGEIE (1 << 1) /* Bit 1: PHY Global Interrupt Enable */ -#define PHIE_PLNKIE (1 << 4) /* Bit 4: PHY Link Change Interrupt Enable */ - -/* PHIR Regiser Bit Definitions */ - -#define PHIR_PGIF (1 << 2) /* Bit 2: PHY Global Interrupt */ -#define PHIR_PLNKIF (1 << 4) /* Bit 4: PHY Link Change Interrupt */ - -/* PHLCON Regiser Bit Definitions */ - /* Bit 0: Reserved */ -#define PHLCON_STRCH (1 << 1) /* Bit 1: LED Pulse Stretching Enable */ -#define PHLCON_LFRQ0 (1 << 2) /* Bit 2: LED Pulse Stretch Time Configuration */ -#define PHLCON_LFRQ1 (1 << 3) /* Bit 3: " " " " " " " " " */ -#define PHLCON_LBCFG0 (1 << 4) /* Bit 4: LEDB Configuration */ -#define PHLCON_LBCFG1 (1 << 5) /* Bit 5: " " " " */ -#define PHLCON_LBCFG2 (1 << 6) /* Bit 6: " " " " */ -#define PHLCON_LBCFG3 (1 << 7) /* Bit 7: " " " " */ -#define PHLCON_LACFG0 (1 << 8) /* Bit 8: LEDA Configuration */ -#define PHLCON_LACFG1 (1 << 9) /* Bit 9: " " " " */ -#define PHLCON_LACFG2 (1 << 10) /* Bit 10: " " " " */ -#define PHLCON_LACFG3 (1 << 11) /* Bit 11: " " " " */ - -/* Packet Memory ************************************************************/ - -/* 8-Kbyte Transmit/Receive Packet Dual Port SRAM */ - -#define PKTMEM_START 0x0000 -#define PKTMEM_END 0x1fff - -/* Ethernet frames are between 64 and 1518 bytes long */ - -#define MIN_FRAMELEN 64 -#define MAX_FRAMELEN 1518 - -/* Packet Control Bits Definitions ******************************************/ - -#define PKTCTRL_POVERRIDE (1 << 0) /* Bit 0: Per Packet Override */ -#define PKTCTRL_PCRCEN (1 << 1) /* Bit 1: Per Packet CRC Enable */ -#define PKTCTRL_PPADEN (1 << 2) /* Bit 2: Per Packet Padding Enable */ -#define PKTCTRL_PHUGEEN (1 << 3) /* Bit 3: Per Packet Huge Frame Enable */ - -/* RX Status Bit Definitions ************************************************/ - -#define RXSTAT_LDEVENT (1 << 0) /* Bit 0: Long event or pack dropped */ - /* Bit 1: Reserved */ -#define RXSTAT_CEPS (1 << 2) /* Bit 2: Carrier event previously seen */ - /* Bit 3: Reserved */ -#define RXSTAT_CRCERROR (1 << 4) /* Bit 4: Frame CRC field bad */ -#define RXSTAT_LENERROR (1 << 5) /* Bit 5: Packet length != data length */ -#define RXSTAT_LENRANGE (1 << 6) /* Bit 6: Type/length field > 1500 bytes */ -#define RXSTAT_OK (1 << 7) /* Bit 7: Packet with valid CRC and no symbol errors */ -#define RXSTAT_MCAST (1 << 8) /* Bit 8: Packet with multicast address */ -#define RXSTAT_BCAST (1 << 9) /* Bit 9: Packet with broadcast address */ -#define RXSTAT_DRIBBLE (1 << 10) /* Bit 10: Additional bits received after packet */ -#define RXSTAT_CTRLFRAME (1 << 11) /* Bit 11: Control frame with valid type/length */ -#define RXSTAT_PAUSE (1 << 12) /* Bit 12: Control frame with pause frame opcde */ -#define RXSTAT_UNKOPCODE (1 << 13) /* Bit 13: Control frame with unknown opcode */ -#define RXSTAT_VLANTYPE (1 << 14) /* Bit 14: Current frame is a VLAN tagged frame */ - /* Bit 15: Zero */ - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_NET_ENC28J60_H */ diff --git a/nuttx/drivers/net/skeleton.c b/nuttx/drivers/net/skeleton.c deleted file mode 100644 index 00ebea35f..000000000 --- a/nuttx/drivers/net/skeleton.c +++ /dev/null @@ -1,692 +0,0 @@ -/**************************************************************************** - * drivers/net/skeleton.c - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#if defined(CONFIG_NET) && defined(CONFIG_NET_skeleton) - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* CONFIG_skeleton_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_skeleton_NINTERFACES -# define CONFIG_skeleton_NINTERFACES 1 -#endif - -/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define skeleton_WDDELAY (1*CLK_TCK) -#define skeleton_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define skeleton_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct uip_eth_hdr *)skel->sk_dev.d_buf) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* The skel_driver_s encapsulates all state information for a single hardware - * interface - */ - -struct skel_driver_s -{ - bool sk_bifup; /* true:ifup false:ifdown */ - WDOG_ID sk_txpoll; /* TX poll timer */ - WDOG_ID sk_txtimeout; /* TX timeout timer */ - - /* This holds the information visible to uIP/NuttX */ - - struct uip_driver_s sk_dev; /* Interface understood by uIP */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct skel_driver_s g_skel[CONFIG_skeleton_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Common TX logic */ - -static int skel_transmit(FAR struct skel_driver_s *skel); -static int skel_uiptxpoll(struct uip_driver_s *dev); - -/* Interrupt handling */ - -static void skel_receive(FAR struct skel_driver_s *skel); -static void skel_txdone(FAR struct skel_driver_s *skel); -static int skel_interrupt(int irq, FAR void *context); - -/* Watchdog timer expirations */ - -static void skel_polltimer(int argc, uint32_t arg, ...); -static void skel_txtimeout(int argc, uint32_t arg, ...); - -/* NuttX callback functions */ - -static int skel_ifup(struct uip_driver_s *dev); -static int skel_ifdown(struct uip_driver_s *dev); -static int skel_txavail(struct uip_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int skel_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -static int skel_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: skel_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * skel - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int skel_transmit(FAR struct skel_driver_s *skel) -{ - /* Verify that the hardware is ready to send another packet. If we get - * here, then we are committed to sending a packet; Higher level logic - * must have assured that there is no transmission in progress. - */ - - /* Increment statistics */ - - /* Send the packet: address=skel->sk_dev.d_buf, length=skel->sk_dev.d_len */ - - /* Enable Tx interrupts */ - - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - - (void)wd_start(skel->sk_txtimeout, skeleton_TXTIMEOUT, skel_txtimeout, 1, (uint32_t)skel); - return OK; -} - -/**************************************************************************** - * Function: skel_uiptxpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from uip_poll(). uip_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int skel_uiptxpoll(struct uip_driver_s *dev) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (skel->sk_dev.d_len > 0) - { - uip_arp_out(&skel->sk_dev); - skel_transmit(skel); - - /* Check if there is room in the device to hold another packet. If not, - * return a non-zero value to terminate the poll. - */ - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: skel_receive - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * skel - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by interrupt handling logic. - * - ****************************************************************************/ - -static void skel_receive(FAR struct skel_driver_s *skel) -{ - do - { - /* Check for errors and update statistics */ - - /* Check if the packet is a valid size for the uIP buffer configuration */ - - /* Copy the data data from the hardware to skel->sk_dev.d_buf. Set - * amount of data in skel->sk_dev.d_len - */ - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(UIP_ETHTYPE_IP6)) -#else - if (BUF->type == HTONS(UIP_ETHTYPE_IP)) -#endif - { - uip_arp_ipin(&skel->sk_dev); - uip_input(&skel->sk_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (skel->sk_dev.d_len > 0) - { - uip_arp_out(&skel->sk_dev); - skel_transmit(skel); - } - } - else if (BUF->type == htons(UIP_ETHTYPE_ARP)) - { - uip_arp_arpin(&skel->sk_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (skel->sk_dev.d_len > 0) - { - skel_transmit(skel); - } - } - } - while (); /* While there are more packets to be processed */ -} - -/**************************************************************************** - * Function: skel_txdone - * - * Description: - * An interrupt was received indicating that the last TX packet(s) is done - * - * Parameters: - * skel - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void skel_txdone(FAR struct skel_driver_s *skel) -{ - /* Check for errors and update statistics */ - - /* If no further xmits are pending, then cancel the TX timeout and - * disable further Tx interrupts. - */ - - wd_cancel(skel->sk_txtimeout); - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&skel->sk_dev, skel_uiptxpoll); -} - -/**************************************************************************** - * Function: skel_interrupt - * - * Description: - * Hardware interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int skel_interrupt(int irq, FAR void *context) -{ - register FAR struct skel_driver_s *skel = &g_skel[0]; - - /* Get and clear interrupt status bits */ - - /* Handle interrupts according to status bit settings */ - - /* Check if we received an incoming packet, if so, call skel_receive() */ - - skel_receive(skel); - - /* Check if a packet transmission just completed. If so, call skel_txdone. - * This may disable further Tx interrupts if there are no pending - * tansmissions. - */ - - skel_txdone(skel); - - return OK; -} - -/**************************************************************************** - * Function: skel_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void skel_txtimeout(int argc, uint32_t arg, ...) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg; - - /* Increment statistics and dump debug info */ - - /* Then reset the hardware */ - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&skel->sk_dev, skel_uiptxpoll); -} - -/**************************************************************************** - * Function: skel_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void skel_polltimer(int argc, uint32_t arg, ...) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg; - - /* Check if there is room in the send another TX packet. We cannot perform - * the TX poll if he are unable to accept another packet for transmission. - */ - - /* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm.. - * might be bug here. Does this mean if there is a transmit in progress, - * we will missing TCP time state updates? - */ - - (void)uip_timer(&skel->sk_dev, skel_uiptxpoll, skeleton_POLLHSEC); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(skel->sk_txpoll, skeleton_WDDELAY, skel_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: skel_ifup - * - * Description: - * NuttX Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int skel_ifup(struct uip_driver_s *dev) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)dev->d_private; - - ndbg("Bringing up: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */ - - /* Set and activate a timer process */ - - (void)wd_start(skel->sk_txpoll, skeleton_WDDELAY, skel_polltimer, 1, (uint32_t)skel); - - /* Enable the Ethernet interrupt */ - - skel->sk_bifup = true; - up_enable_irq(CONFIG_skeleton_IRQ); - return OK; -} - -/**************************************************************************** - * Function: skel_ifdown - * - * Description: - * NuttX Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int skel_ifdown(struct uip_driver_s *dev) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - up_disable_irq(CONFIG_skeleton_IRQ); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(skel->sk_txpoll); - wd_cancel(skel->sk_txtimeout); - - /* Put the EMAC in its reset, non-operational state. This should be - * a known configuration that will guarantee the skel_ifup() always - * successfully brings the interface back up. - */ - - /* Mark the device "down" */ - - skel->sk_bifup = false; - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: skel_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int skel_txavail(struct uip_driver_s *dev) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable interrupts because this function may be called from interrupt - * level processing. - */ - - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (skel->sk_bifup) - { - /* Check if there is room in the hardware to hold another outgoing packet. */ - - /* If so, then poll uIP for new XMIT data */ - - (void)uip_poll(&skel->sk_dev, skel_uiptxpoll); - } - - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: skel_addmac - * - * Description: - * NuttX Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int skel_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Function: skel_rmmac - * - * Description: - * NuttX Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int skel_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: skel_initialize - * - * Description: - * Initialize the Ethernet controller and driver - * - * Parameters: - * intf - In the case where there are multiple EMACs, this value - * identifies which EMAC is to be initialized. - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -int skel_initialize(int intf) -{ - struct skel_driver_s *priv; - - /* Get the interface structure associated with this interface number. */ - - DEBUGASSERT(inf < CONFIG_skeleton_NINTERFACES); - priv = &g_skel[intf]; - - /* Check if a Ethernet chip is recognized at its I/O base */ - - /* Attach the IRQ to the driver */ - - if (irq_attach(CONFIG_skeleton_IRQ, skel_interrupt)) - { - /* We could not attach the ISR to the interrupt */ - - return -EAGAIN; - } - - /* Initialize the driver structure */ - - memset(priv, 0, sizeof(struct skel_driver_s)); - priv->sk_dev.d_ifup = skel_ifup; /* I/F up (new IP address) callback */ - priv->sk_dev.d_ifdown = skel_ifdown; /* I/F down callback */ - priv->sk_dev.d_txavail = skel_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - priv->sk_dev.d_addmac = skel_addmac; /* Add multicast MAC address */ - priv->sk_dev.d_rmmac = skel_rmmac; /* Remove multicast MAC address */ -#endif - priv->sk_dev.d_private = (void*)g_skel; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - priv->sk_txpoll = wd_create(); /* Create periodic poll timer */ - priv->sk_txtimeout = wd_create(); /* Create TX timeout timer */ - - /* Put the interface in the down state. This usually amounts to resetting - * the device and/or calling skel_ifdown(). - */ - - /* Read the MAC address from the hardware into priv->sk_dev.d_mac.ether_addr_octet */ - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - (void)netdev_register(&priv->sk_dev); - return OK; -} - -#endif /* CONFIG_NET && CONFIG_NET_skeleton */ diff --git a/nuttx/drivers/net/slip.c b/nuttx/drivers/net/slip.c deleted file mode 100644 index 31f44cbb9..000000000 --- a/nuttx/drivers/net/slip.c +++ /dev/null @@ -1,1017 +0,0 @@ -/**************************************************************************** - * drivers/net/slip.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Reference: RFC 1055 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#if defined(CONFIG_NET) && defined(CONFIG_NET_SLIP) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* NOTE: Slip requires UART hardware handshake. If hardware handshake is - * not available with your UART, then you might try the 'slattach' option - * -L which enable "3-wire operation." That allows operation without the - * hardware handshake (but with the possibility of data overrun). - */ - -/* Configuration ************************************************************/ - -#if UIP_LLH_LEN > 0 -# error "UIP_LLH_LEN must be set to zero" -#endif - -#ifndef CONFIG_NET_NOINTS -# warning "CONFIG_NET_NOINTS must be set" -#endif - -#ifndef CONFIG_NET_MULTIBUFFER -# warning "CONFIG_NET_MULTIBUFFER must be set" -#endif - -#ifndef CONFIG_SLIP_STACKSIZE -# define CONFIG_SLIP_STACKSIZE 2048 -#endif - -#ifndef CONFIG_SLIP_DEFPRIO -# define CONFIG_SLIP_DEFPRIO 128 -#endif - -/* The Linux slip module hard-codes its MTU size to 296 (40 bytes for the - * IP+TPC headers plus 256 bytes of data). So you might as well set - * CONFIG_NET_BUFSIZE to 296 as well. - * - * There may be an issue with this setting, however. I see that Linux uses - * a MTU of 296 and window of 256, but actually only sends 168 bytes of data: - * 40 + 128. I believe that is to allow for the 2x worst cast packet - * expansion. Ideally we would like to advertise the 256 MSS, but restrict - * uIP to 128 bytes (possibly by modifying the uip_mss() macro). - */ - -#if CONFIG_NET_BUFSIZE < 296 -# error "CONFIG_NET_BUFSIZE >= 296 is required" -#elif CONFIG_NET_BUFSIZE > 296 -# warning "CONFIG_NET_BUFSIZE == 296 is optimal" -#endif - -/* CONFIG_SLIP_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_SLIP_NINTERFACES -# define CONFIG_SLIP_NINTERFACES 1 -#endif - -/* SLIP special character codes *******************************************/ - -#define SLIP_END 0300 /* Indicates end of packet */ -#define SLIP_ESC 0333 /* Indicates byte stuffing */ -#define SLIP_ESC_END 0334 /* ESC ESC_END means SLIP_END data byte */ -#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */ - -/* General driver definitions **********************************************/ - -/* TX poll delay = 1 second = 1000000 microseconds. */ - -#define SLIP_WDDELAY (1*1000000) -#define SLIP_POLLHSEC (1*2) - -/* Statistics helper */ - -#ifdef CONFIG_NET_STATISTICS -# define SLIP_STAT(p,f) (p->stats.f)++ -#else -# define SLIP_STAT(p,f) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Driver statistics */ - -#ifdef CONFIG_NET_STATISTICS -struct slip_statistics_s -{ - uint32_t transmitted; /* Number of packets transmitted */ - uint32_t received /* Number of packets received */ -}; -#endif - -/* The slip_driver_s encapsulates all state information for a single hardware - * interface - */ - -struct slip_driver_s -{ - volatile bool bifup; /* true:ifup false:ifdown */ - int fd; /* TTY file descriptor */ - pid_t rxpid; /* Receiver thread ID */ - pid_t txpid; /* Transmitter thread ID */ - sem_t waitsem; /* Mutually exclusive access to uIP */ - uint16_t rxlen; /* The number of bytes in rxbuf */ - - /* Driver statistics */ - -#ifdef CONFIG_NET_STATISTICS - struct slip_statistics_s stats; -#endif - - /* This holds the information visible to uIP/NuttX */ - - struct uip_driver_s dev; /* Interface understood by uIP */ - uint8_t rxbuf[CONFIG_NET_BUFSIZE + 2]; - uint8_t txbuf[CONFIG_NET_BUFSIZE + 2]; -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - - /* We really should get rid of CONFIG_SLIP_NINTERFACES and, instead, - * kmalloc() new interface instances as needed. - */ - -static struct slip_driver_s g_slip[CONFIG_SLIP_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void slip_semtake(FAR struct slip_driver_s *priv); - -/* Common TX logic */ - -static void slip_write(FAR struct slip_driver_s *priv, const uint8_t *buffer, int len); -static void slip_putc(FAR struct slip_driver_s *priv, int ch); -static int slip_transmit(FAR struct slip_driver_s *priv); -static int slip_uiptxpoll(struct uip_driver_s *dev); -static void slip_txtask(int argc, char *argv[]); - -/* Packet receiver task */ - -static int slip_getc(FAR struct slip_driver_s *priv); -static inline void slip_receive(FAR struct slip_driver_s *priv); -static int slip_rxtask(int argc, char *argv[]); - -/* NuttX callback functions */ - -static int slip_ifup(struct uip_driver_s *dev); -static int slip_ifdown(struct uip_driver_s *dev); -static int slip_txavail(struct uip_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int slip_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -static int slip_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: slip_semtake - ****************************************************************************/ - -static void slip_semtake(FAR struct slip_driver_s *priv) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(&priv->waitsem) != 0) - { - /* The only case that an error should occur here is if - * the wait was awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -#define slip_semgive(p) sem_post(&(p)->waitsem); - -/**************************************************************************** - * Function: slip_write - * - * Description: - * Just an inline wrapper around fwrite with error checking. - * - * Parameters: - * priv - Reference to the driver state structure - * buffer - Buffer data to send - * len - Buffer length in bytes - * - ****************************************************************************/ - -static inline void slip_write(FAR struct slip_driver_s *priv, - const uint8_t *buffer, int len) -{ - /* Handle the case where the write is awakened by a signal */ - - while (write(priv->fd, buffer, len) < 0) - { - DEBUGASSERT(errno == EINTR); - } -} - -/**************************************************************************** - * Function: slip_putc - * - * Description: - * Just an inline wrapper around putc with error checking. - * - * Parameters: - * priv - Reference to the driver state structure - * ch - The character to send - * - ****************************************************************************/ - -static inline void slip_putc(FAR struct slip_driver_s *priv, int ch) -{ - uint8_t buffer = (uint8_t)ch; - slip_write(priv, &buffer, 1); -} - -/**************************************************************************** - * Function: slip_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - ****************************************************************************/ - -static int slip_transmit(FAR struct slip_driver_s *priv) -{ - uint8_t *src; - uint8_t *start; - uint8_t esc; - int remaining; - int len; - - /* Increment statistics */ - - nvdbg("Sending packet size %d\n", priv->dev.d_len); - SLIP_STAT(priv, transmitted); - - /* Send an initial END character to flush out any data that may have - * accumulated in the receiver due to line noise - */ - - slip_putc(priv, SLIP_END); - - /* For each byte in the packet, send the appropriate character sequence */ - - src = priv->dev.d_buf; - remaining = priv->dev.d_len; - start = src; - len = 0; - - while (remaining-- > 0) - { - switch (*src) - { - /* If it's the same code as an END character, we send a special two - * character code so as not to make the receiver think we sent an - * END - */ - - case SLIP_END: - esc = SLIP_ESC_END; - goto escape; - - /* If it's the same code as an ESC character, we send a special two - * character code so as not to make the receiver think we sent an - * ESC - */ - - case SLIP_ESC: - esc = SLIP_ESC_ESC; - - escape: - { - /* Flush any unsent data */ - - if (len > 0) - { - slip_write(priv, start, len); - - /* Reset */ - - start = src + 1; - len = 0; - } - - /* Then send the escape sequence */ - - slip_putc(priv, SLIP_ESC); - slip_putc(priv, esc); - } - break; - - /* otherwise, just bump up the count */ - - default: - len++; - break; - } - - /* Point to the next character in the packet */ - - src++; - } - - /* We have looked at every character in the packet. Now flush any unsent - * data - */ - - if (len > 0) - { - slip_write(priv, start, len); - } - - /* And send the END token */ - - slip_putc(priv, SLIP_END); - return OK; -} - -/**************************************************************************** - * Function: slip_uiptxpoll - * - * Description: - * Check if uIP has any outgoing packets ready to send. This is a - * callback from uip_poll(). uip_poll() may be called: - * - * 1. When the preceding TX packet send is complete, or - * 2. When the preceding TX packet send times o ]ut and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * The initiator of the poll holds the priv->waitsem; - * - ****************************************************************************/ - -static int slip_uiptxpoll(struct uip_driver_s *dev) -{ - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (priv->dev.d_len > 0) - { - slip_transmit(priv); - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: slip_txtask - * - * Description: - * Polling and transmission is performed on tx thread. - * - * Parameters: - * arg - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void slip_txtask(int argc, char *argv[]) -{ - FAR struct slip_driver_s *priv; - unsigned int index = *(argv[1]) - '0'; - uip_lock_t flags; - - ndbg("index: %d\n", index); - DEBUGASSERT(index < CONFIG_SLIP_NINTERFACES); - - /* Get our private data structure instance and wake up the waiting - * initialization logic. - */ - - priv = &g_slip[index]; - slip_semgive(priv); - - /* Loop forever */ - - for (;;) - { - /* Wait for the timeout to expire (or until we are signaled by by */ - - usleep(SLIP_WDDELAY); - - /* Is the interface up? */ - - if (priv->bifup) - { - /* Get exclusive access to uIP (if it it is already being used - * slip_rxtask, then we have to wait). - */ - - slip_semtake(priv); - - /* Poll uIP for new XMIT data. BUG: We really need to calculate - * the number of hsecs! When we are awakened by slip_txavail, the - * number will be smaller; when we have to wait for the semaphore - * (above), it may be larger. - */ - - flags = uip_lock(); - priv->dev.d_buf = priv->txbuf; - (void)uip_timer(&priv->dev, slip_uiptxpoll, SLIP_POLLHSEC); - uip_unlock(flags); - slip_semgive(priv); - } - } -} - -/**************************************************************************** - * Function: slip_getc - * - * Description: - * Get one byte from the serial input. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * The returned byte - * - ****************************************************************************/ - -static inline int slip_getc(FAR struct slip_driver_s *priv) -{ - uint8_t ch; - - while (read(priv->fd, &ch, 1) < 0) - { - DEBUGASSERT(errno == EINTR); - } - - return (int)ch; -} - -/**************************************************************************** - * Function: slip_receive - * - * Description: - * Read a packet from the serial input - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - ****************************************************************************/ - -static inline void slip_receive(FAR struct slip_driver_s *priv) -{ - uint8_t ch; - - /* Copy the data data from the hardware to to the RX buffer until we - * put together a whole packet. Make sure not to copy them into the - * packet if we run out of room. - */ - - nvdbg("Receiving packet\n"); - for (;;) - { - /* Get the next character in the stream. */ - - ch = slip_getc(priv); - - /* Handle bytestuffing if necessary */ - - switch (ch) - { - /* If it's an END character then we're done with the packet. - * (OR we are just starting a packet) - */ - - case SLIP_END: - nvdbg("END\n"); - - /* A minor optimization: if there is no data in the packet, ignore - * it. This is meant to avoid bothering IP with all the empty - * packets generated by the duplicate END characters which are in - * turn sent to try to detect line noise. - */ - - if (priv->rxlen > 0) - { - nvdbg("Received packet size %d\n", priv->rxlen); - return; - } - break; - - /* if it's the same code as an ESC character, wait and get another - * character and then figure out what to store in the packet based - * on that. - */ - - case SLIP_ESC: - nvdbg("ESC\n"); - ch = slip_getc(priv); - - /* if "ch" is not one of these two, then we have a protocol - * violation. The best bet seems to be to leave the byte alone - * and just stuff it into the packet - */ - - switch (ch) - { - case SLIP_ESC_END: - nvdbg("ESC-END\n"); - ch = SLIP_END; - break; - case SLIP_ESC_ESC: - nvdbg("ESC-ESC\n"); - ch = SLIP_ESC; - break; - default: - ndbg("ERROR: Protocol violation: %02x\n", ch); - break; - } - - /* Here we fall into the default handler and let it store the - * character for us - */ - - default: - if (priv->rxlen < CONFIG_NET_BUFSIZE+2) - { - priv->rxbuf[priv->rxlen++] = ch; - } - break; - } - } -} - -/**************************************************************************** - * Function: slip_rxtask - * - * Description: - * Wait for incoming data. - * - * Parameters: - * argc - * argv - * - * Returned Value: - * (Does not return) - * - * Assumptions: - * - ****************************************************************************/ - -static int slip_rxtask(int argc, char *argv[]) -{ - FAR struct slip_driver_s *priv; - unsigned int index = *(argv[1]) - '0'; - uip_lock_t flags; - int ch; - - ndbg("index: %d\n", index); - DEBUGASSERT(index < CONFIG_SLIP_NINTERFACES); - - /* Get our private data structure instance and wake up the waiting - * initialization logic. - */ - - priv = &g_slip[index]; - slip_semgive(priv); - - /* Loop forever */ - - for (;;) - { - /* Wait for the next character to be available on the input stream. */ - - nvdbg("Waiting...\n"); - ch = slip_getc(priv); - - /* Ignore any input that we receive before the interface is up. */ - - if (!priv->bifup) - { - continue; - } - - /* We have something... - * - * END characters may appear at packet boundaries BEFORE as well as - * after the beginning of the packet. This is normal and expected. - */ - - if (ch == SLIP_END) - { - priv->rxlen = 0; - } - - /* Otherwise, we are in danger of being out-of-sync. Apparently the - * leading END character is optional. Let's try to continue. - */ - - else - { - priv->rxbuf[0] = (uint8_t)ch; - priv->rxlen = 1; - } - - /* Copy the data data from the hardware to priv->rxbuf until we put - * together a whole packet. - */ - - slip_receive(priv); - SLIP_STAT(priv, received); - - /* All packets are assumed to be IP packets (we don't have a choice.. - * there is no Ethernet header containing the EtherType). So pass the - * received packet on for IP processing -- but only if it is big - * enough to hold an IP header. - */ - - if (priv->rxlen >= UIP_IPH_LEN) - { - /* Handle the IP input. Get exclusive access to uIP. */ - - slip_semtake(priv); - priv->dev.d_buf = priv->rxbuf; - priv->dev.d_len = priv->rxlen; - - flags = uip_lock(); - uip_input(&priv->dev); - - /* If the above function invocation resulted in data that should - * be sent out on the network, the field d_len will set to a - * value > 0. NOTE that we are transmitting using the RX buffer! - */ - - if (priv->dev.d_len > 0) - { - slip_transmit(priv); - } - uip_unlock(flags); - slip_semgive(priv); - } - else - { - SLIP_STAT(priv, rxsmallpacket); - } - } - - /* We won't get here */ - - return OK; -} - -/**************************************************************************** - * Function: slip_ifup - * - * Description: - * NuttX Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int slip_ifup(struct uip_driver_s *dev) -{ - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - - ndbg("Bringing up: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Mark the interface up */ - - priv->bifup = true; - return OK; -} - -/**************************************************************************** - * Function: slip_ifdown - * - * Description: - * NuttX Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int slip_ifdown(struct uip_driver_s *dev) -{ - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - - /* Mark the device "down" */ - - priv->bifup = false; - return OK; -} - -/**************************************************************************** - * Function: slip_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - ****************************************************************************/ - -static int slip_txavail(struct uip_driver_s *dev) -{ - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - - /* Ignore the notification if the interface is not yet up */ - - if (priv->bifup) - { - /* Wake up the TX polling thread */ - - kill(priv->txpid, SIGALRM); - } - - return OK; -} - -/**************************************************************************** - * Function: slip_addmac - * - * Description: - * NuttX Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int slip_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Function: slip_rmmac - * - * Description: - * NuttX Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int slip_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: slip_initialize - * - * Description: - * Instantiate a SLIP network interface. - * - * Parameters: - * intf - In the case where there are multiple SLIP interfaces, this value - * identifies which is to be initialized. The network name will be, - * for example, "/dev/slip5" for intf == 5 - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -int slip_initialize(int intf, const char *devname) -{ - struct slip_driver_s *priv; - char buffer[8]; - const char *argv[2]; - - /* Get the interface structure associated with this interface number. */ - - DEBUGASSERT(intf < CONFIG_SLIP_NINTERFACES); - priv = &g_slip[intf]; - - /* Initialize the driver structure */ - - memset(priv, 0, sizeof(struct slip_driver_s)); - priv->dev.d_ifup = slip_ifup; /* I/F up (new IP address) callback */ - priv->dev.d_ifdown = slip_ifdown; /* I/F down callback */ - priv->dev.d_txavail = slip_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - priv->dev.d_addmac = slip_addmac; /* Add multicast MAC address */ - priv->dev.d_rmmac = slip_rmmac; /* Remove multicast MAC address */ -#endif - priv->dev.d_private = priv; /* Used to recover private state from dev */ - - /* Open the device */ - - priv->fd = open(devname, O_RDWR, 0666); - if (priv->fd < 0) - { - ndbg("ERROR: Failed to open %s: %d\n", devname, errno); - return -errno; - } - - /* Initialize the wait semaphore */ - - sem_init(&priv->waitsem, 0, 0); - - /* Put the interface in the down state. This usually amounts to resetting - * the device and/or calling slip_ifdown(). - */ - - slip_ifdown(&priv->dev); - - /* Start the SLIP receiver task */ - - snprintf(buffer, 8, "%d", intf); - argv[0] = buffer; - argv[1] = NULL; - -#ifndef CONFIG_CUSTOM_STACK - priv->rxpid = task_create("rxslip", CONFIG_SLIP_DEFPRIO, - CONFIG_SLIP_STACKSIZE, (main_t)slip_rxtask, argv); -#else - priv->rxpid = task_create("rxslip", CONFIG_SLIP_DEFPRIO, - (main_t)slip_rxtask, argv); -#endif - if (priv->rxpid < 0) - { - ndbg("ERROR: Failed to start receiver task\n"); - return -errno; - } - - /* Wait and make sure that the receive task is started. */ - - slip_semtake(priv); - - /* Start the SLIP transmitter task */ - -#ifndef CONFIG_CUSTOM_STACK - priv->txpid = task_create("txslip", CONFIG_SLIP_DEFPRIO, - CONFIG_SLIP_STACKSIZE, (main_t)slip_txtask, argv); -#else - priv->txpid = task_create("txslip", CONFIG_SLIP_DEFPRIO, - (main_t)slip_txtask, argv); -#endif - if (priv->txpid < 0) - { - ndbg("ERROR: Failed to start receiver task\n"); - return -errno; - } - - /* Wait and make sure that the transmit task is started. */ - - slip_semtake(priv); - - /* Bump the semaphore count so that it can now be used as a mutex */ - - slip_semgive(priv); - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - (void)netdev_register(&priv->dev); - - /* When the RX and TX tasks were created, the TTY file descriptor was - * dup'ed for each task. This task no longer needs the file descriptor - * and we can safely close it. - */ - - close(priv->fd); - return OK; -} - -#endif /* CONFIG_NET && CONFIG_NET_SLIP */ - diff --git a/nuttx/drivers/net/vnet.c b/nuttx/drivers/net/vnet.c deleted file mode 100644 index e05a39675..000000000 --- a/nuttx/drivers/net/vnet.c +++ /dev/null @@ -1,672 +0,0 @@ -/**************************************************************************** - * drivers/net/vnet.c - * - * Copyright (C) 2011 Yu Qiang. All rights reserved. - * Author: Yu Qiang - * - * This file is a part of NuttX: - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#if defined(CONFIG_NET) && defined(CONFIG_NET_VNET) - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* CONFIG_VNET_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_VNET_NINTERFACES -# define CONFIG_VNET_NINTERFACES 1 -#endif - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define VNET_WDDELAY (1*CLK_TCK) -#define VNET_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define VNET_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct uip_eth_hdr *)vnet->sk_dev.d_buf) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* The vnet_driver_s encapsulates all state information for a single hardware - * interface - */ - -struct vnet_driver_s -{ - bool sk_bifup; /* true:ifup false:ifdown */ - WDOG_ID sk_txpoll; /* TX poll timer */ - //WDOG_ID sk_txtimeout; /* TX timeout timer */ - - /* This holds the information visible to uIP/NuttX */ - struct rgmp_vnet *vnet; - struct uip_driver_s sk_dev; /* Interface understood by uIP */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct vnet_driver_s g_vnet[CONFIG_VNET_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Common TX logic */ - -static int vnet_transmit(FAR struct vnet_driver_s *vnet); -static int vnet_uiptxpoll(struct uip_driver_s *dev); - -/* Interrupt handling */ - -static void vnet_txdone(FAR struct vnet_driver_s *vnet); - -/* Watchdog timer expirations */ - -static void vnet_polltimer(int argc, uint32_t arg, ...); -static void vnet_txtimeout(int argc, uint32_t arg, ...); - -/* NuttX callback functions */ - -static int vnet_ifup(struct uip_driver_s *dev); -static int vnet_ifdown(struct uip_driver_s *dev); -static int vnet_txavail(struct uip_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int vnet_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -static int vnet_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac); -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: vnet_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * vnet - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int vnet_transmit(FAR struct vnet_driver_s *vnet) -{ - int err; - - /* Verify that the hardware is ready to send another packet. If we get - * here, then we are committed to sending a packet; Higher level logic - * must have assured that there is not transmission in progress. - */ - - /* Increment statistics */ - - /* Send the packet: address=vnet->sk_dev.d_buf, length=vnet->sk_dev.d_len */ - err = vnet_xmit(vnet->vnet, (char *)vnet->sk_dev.d_buf, vnet->sk_dev.d_len); - if (err) { - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - //(void)wd_start(vnet->sk_txtimeout, VNET_TXTIMEOUT, vnet_txtimeout, 1, (uint32_t)vnet); - - // When vnet_xmit fail, it means TX buffer is full. Watchdog - // is of no use here because no TX done INT will happen. So - // we reset the TX buffer directly. -#ifdef CONFIG_DEBUG - cprintf("VNET: TX buffer is full\n"); -#endif - return ERROR; - } - else { - // this step may be unnecessary here - vnet_txdone(vnet); - } - - return OK; -} - -/**************************************************************************** - * Function: vnet_uiptxpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from uip_poll(). uip_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int vnet_uiptxpoll(struct uip_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (vnet->sk_dev.d_len > 0) - { - uip_arp_out(&vnet->sk_dev); - vnet_transmit(vnet); - - /* Check if there is room in the device to hold another packet. If not, - * return a non-zero value to terminate the poll. - */ - if (vnet_is_txbuff_full(vnet->vnet)) - return 1; - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: rtos_vnet_recv - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * vnet - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by interrupt handling logic. - * - ****************************************************************************/ - -void rtos_vnet_recv(struct rgmp_vnet *rgmp_vnet, char *data, int len) -{ - struct vnet_driver_s *vnet = rgmp_vnet->priv; - - do { - /* Check for errors and update statistics */ - - /* Check if the packet is a valid size for the uIP buffer configuration */ - if (len > CONFIG_NET_BUFSIZE || len < 14) { -#ifdef CONFIG_DEBUG - cprintf("VNET: receive invalid packet of size %d\n", len); -#endif - return; - } - - // Copy the data data from the hardware to vnet->sk_dev.d_buf. Set - // amount of data in vnet->sk_dev.d_len - memcpy(vnet->sk_dev.d_buf, data, len); - vnet->sk_dev.d_len = len; - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(UIP_ETHTYPE_IP6)) -#else - if (BUF->type == HTONS(UIP_ETHTYPE_IP)) -#endif - { - uip_arp_ipin(&vnet->sk_dev); - uip_input(&vnet->sk_dev); - - // If the above function invocation resulted in data that should be - // sent out on the network, the field d_len will set to a value > 0. - if (vnet->sk_dev.d_len > 0) { - uip_arp_out(&vnet->sk_dev); - vnet_transmit(vnet); - } - } - else if (BUF->type == htons(UIP_ETHTYPE_ARP)) { - uip_arp_arpin(&vnet->sk_dev); - - // If the above function invocation resulted in data that should be - // sent out on the network, the field d_len will set to a value > 0. - if (vnet->sk_dev.d_len > 0) { - vnet_transmit(vnet); - } - } - } - while (0); /* While there are more packets to be processed */ -} - -/**************************************************************************** - * Function: vnet_txdone - * - * Description: - * An interrupt was received indicating that the last TX packet(s) is done - * - * Parameters: - * vnet - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void vnet_txdone(FAR struct vnet_driver_s *vnet) -{ - /* Check for errors and update statistics */ - - /* If no further xmits are pending, then cancel the TX timeout and - * disable further Tx interrupts. - */ - - //wd_cancel(vnet->sk_txtimeout); - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&vnet->sk_dev, vnet_uiptxpoll); -} - -/**************************************************************************** - * Function: vnet_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void vnet_txtimeout(int argc, uint32_t arg, ...) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)arg; - - /* Increment statistics and dump debug info */ - - /* Then reset the hardware */ - - /* Then poll uIP for new XMIT data */ - - (void)uip_poll(&vnet->sk_dev, vnet_uiptxpoll); -} - -/**************************************************************************** - * Function: vnet_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void vnet_polltimer(int argc, uint32_t arg, ...) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)arg; - - /* Check if there is room in the send another TX packet. We cannot perform - * the TX poll if he are unable to accept another packet for transmission. - */ - if (vnet_is_txbuff_full(vnet->vnet)) { -#ifdef CONFIG_DEBUG - cprintf("VNET: TX buffer is full\n"); -#endif - return; - } - - /* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm.. - * might be bug here. Does this mean if there is a transmit in progress, - * we will missing TCP time state updates? - */ - - (void)uip_timer(&vnet->sk_dev, vnet_uiptxpoll, VNET_POLLHSEC); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(vnet->sk_txpoll, VNET_WDDELAY, vnet_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: vnet_ifup - * - * Description: - * NuttX Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int vnet_ifup(struct uip_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - ndbg("Bringing up: %d.%d.%d.%d\n", - dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, - (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); - - /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */ - - /* Set and activate a timer process */ - - (void)wd_start(vnet->sk_txpoll, VNET_WDDELAY, vnet_polltimer, 1, (uint32_t)vnet); - - vnet->sk_bifup = true; - return OK; -} - -/**************************************************************************** - * Function: vnet_ifdown - * - * Description: - * NuttX Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int vnet_ifdown(struct uip_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(vnet->sk_txpoll); - //wd_cancel(vnet->sk_txtimeout); - - /* Put the the EMAC is its reset, non-operational state. This should be - * a known configuration that will guarantee the vnet_ifup() always - * successfully brings the interface back up. - */ - - /* Mark the device "down" */ - - vnet->sk_bifup = false; - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: vnet_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int vnet_txavail(struct uip_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable interrupts because this function may be called from interrupt - * level processing. - */ - - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (vnet->sk_bifup) - { - /* Check if there is room in the hardware to hold another outgoing packet. */ - if (vnet_is_txbuff_full(vnet->vnet)) { -#ifdef CONFIG_DEBUG - cprintf("VNET: TX buffer is full\n"); -#endif - goto out; - } - - /* If so, then poll uIP for new XMIT data */ - - (void)uip_poll(&vnet->sk_dev, vnet_uiptxpoll); - } - -out: - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: vnet_addmac - * - * Description: - * NuttX Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int vnet_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Function: vnet_rmmac - * - * Description: - * NuttX Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the NuttX driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int vnet_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: vnet_initialize - * - * Description: - * Initialize the Ethernet controller and driver - * - * Parameters: - * intf - In the case where there are multiple EMACs, this value - * identifies which EMAC is to be initialized. - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -int vnet_init(struct rgmp_vnet *vnet) -{ - struct vnet_driver_s *priv; - static int i = 0; - - if (i >= CONFIG_VNET_NINTERFACES) - return -1; - - priv = &g_vnet[i++]; - - /* Initialize the driver structure */ - - memset(priv, 0, sizeof(struct vnet_driver_s)); - priv->sk_dev.d_ifup = vnet_ifup; /* I/F down callback */ - priv->sk_dev.d_ifdown = vnet_ifdown; /* I/F up (new IP address) callback */ - priv->sk_dev.d_txavail = vnet_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - priv->sk_dev.d_addmac = vnet_addmac; /* Add multicast MAC address */ - priv->sk_dev.d_rmmac = vnet_rmmac; /* Remove multicast MAC address */ -#endif - priv->sk_dev.d_private = (void*)priv; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - priv->sk_txpoll = wd_create(); /* Create periodic poll timer */ - //priv->sk_txtimeout = wd_create(); /* Create TX timeout timer */ - - priv->vnet = vnet; - vnet->priv = priv; - - /* Register the device with the OS */ - - (void)netdev_register(&priv->sk_dev); - - return 0; -} - -#endif /* CONFIG_NET && CONFIG_NET_VNET */ diff --git a/nuttx/drivers/pipes/Kconfig b/nuttx/drivers/pipes/Kconfig deleted file mode 100644 index ae2bf3130..000000000 --- a/nuttx/drivers/pipes/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# diff --git a/nuttx/drivers/pipes/Make.defs b/nuttx/drivers/pipes/Make.defs deleted file mode 100644 index 836505481..000000000 --- a/nuttx/drivers/pipes/Make.defs +++ /dev/null @@ -1,46 +0,0 @@ -############################################################################ -# drivers/pipes/Make.defs -# -# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) - -# Include pipe driver - -CSRCS += pipe.c fifo.c pipe_common.c - -# Include pipe build support - -DEPPATH += --dep-path pipes -VPATH += :pipes -endif diff --git a/nuttx/drivers/pipes/fifo.c b/nuttx/drivers/pipes/fifo.c deleted file mode 100644 index 03aafd0f0..000000000 --- a/nuttx/drivers/pipes/fifo.c +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** - * drivers/pipes/fifo.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include "pipe_common.h" - -#if CONFIG_DEV_PIPE_SIZE > 0 - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations fifo_fops = -{ - pipecommon_open, /* open */ - pipecommon_close, /* close */ - pipecommon_read, /* read */ - pipecommon_write, /* write */ - 0, /* seek */ - 0 /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , pipecommon_poll /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mkfifo - * - * Description: - * mkfifo() makes a FIFO device driver file with name 'pathname.' Unlike - * Linux, a NuttX FIFO is not a special file type but simply a device driver - * instance. 'mode' specifies the FIFO's permissions. - * - * Once the FIFO has been created by mkfifo(), any thread can open it for - * reading or writing, in the same way as an ordinary file. However, it must - * have been opened from both reading and writing before input or output - * can be performed. This FIFO implementation will block all attempts to - * open a FIFO read-only until at least one thread has opened the FIFO for - * writing. - * - * If all threads that write to the FIFO have closed, subsequent calls to - * read() on the FIFO will return 0 (end-of-file). - * - * Inputs: - * pathname - The full path to the FIFO instance to attach to or to create - * (if not already created). - * mode - Ignored for now - * - * Return: - * 0 is returned on success; otherwise, -1 is returned with errno set - * appropriately. - * - ****************************************************************************/ - -int mkfifo(FAR const char *pathname, mode_t mode) -{ - struct pipe_dev_s *dev; - int ret; - - /* Allocate and initialize a new device structure instance */ - - dev = pipecommon_allocdev(); - if (!dev) - { - return -ENOMEM; - } - - ret = register_driver(pathname, &fifo_fops, mode, (void*)dev); - if (ret != 0) - { - pipecommon_freedev(dev); - } - - return ret; -} - -#endif /* CONFIG_DEV_PIPE_SIZE > 0 */ diff --git a/nuttx/drivers/pipes/pipe.c b/nuttx/drivers/pipes/pipe.c deleted file mode 100644 index 20c160475..000000000 --- a/nuttx/drivers/pipes/pipe.c +++ /dev/null @@ -1,286 +0,0 @@ -/**************************************************************************** - * drivers/pipes/pipe.c - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Compilation Switches - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "pipe_common.h" - -#if CONFIG_DEV_PIPE_SIZE > 0 - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -#define MAX_PIPES 32 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int pipe_close(FAR struct file *filep); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations pipe_fops = -{ - pipecommon_open, /* open */ - pipe_close, /* close */ - pipecommon_read, /* read */ - pipecommon_write, /* write */ - 0, /* seek */ - 0 /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , pipecommon_poll /* poll */ -#endif -}; - -static sem_t g_pipesem = { 1 }; -static uint32_t g_pipeset = 0; -static uint32_t g_pipecreated = 0; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pipe_allocate - ****************************************************************************/ - -static inline int pipe_allocate(void) -{ - int pipeno; - int ret = -ENFILE; - - for (pipeno = 0; pipeno < MAX_PIPES; pipeno++) - { - if ((g_pipeset & (1 << pipeno)) == 0) - { - g_pipeset |= (1 << pipeno); - ret = pipeno; - break; - } - } - - return ret; -} - -/**************************************************************************** - * Name: pipe_free - ****************************************************************************/ - -static inline void pipe_free(int pipeno) -{ - int ret = sem_wait(&g_pipesem); - if (ret == 0) - { - g_pipeset &= ~(1 << pipeno); - (void)sem_post(&g_pipesem); - } -} - -/**************************************************************************** - * Name: pipe_close - ****************************************************************************/ - -static int pipe_close(FAR struct file *filep) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; - int ret; - - /* Some sanity checking */ -#if CONFIG_DEBUG - if (!dev) - { - return -EBADF; - } -#endif - - /* Perform common close operations */ - - ret = pipecommon_close(filep); - if (ret == 0 && dev->d_refs == 0) - { - /* Release the pipe when there are no further open references to it. */ - - pipe_free(dev->d_pipeno); - } - - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pipe - * - * Description: - * pipe() creates a pair of file descriptors, pointing to a pipe inode, and - * places them in the array pointed to by 'filedes'. filedes[0] is for reading, - * filedes[1] is for writing. - * - * Inputs: - * filedes[2] - The user provided array in which to catch the pipe file - * descriptors - * - * Return: - * 0 is returned on success; otherwise, -1 is returned with errno set - * appropriately. - * - ****************************************************************************/ - -int pipe(int filedes[2]) -{ - struct pipe_dev_s *dev = NULL; - char devname[16]; - int pipeno; - int err; - int ret; - - /* Get exclusive access to the pipe allocation data */ - - ret = sem_wait(&g_pipesem); - if (ret < 0) - { - /* sem_wait() will have already set errno */ - - return ERROR; - } - - /* Allocate a minor number for the pipe device */ - - pipeno = pipe_allocate(); - if (pipeno < 0) - { - (void)sem_post(&g_pipesem); - err = -pipeno; - goto errout; - } - - /* Create a pathname to the pipe device */ - - sprintf(devname, "/dev/pipe%d", pipeno); - - /* Check if the pipe device has already been created */ - - if ((g_pipecreated & (1 << pipeno)) == 0) - { - /* No.. Allocate and initialize a new device structure instance */ - - dev = pipecommon_allocdev(); - if (!dev) - { - (void)sem_post(&g_pipesem); - err = ENOMEM; - goto errout_with_pipe; - } - - dev->d_pipeno = pipeno; - - /* Register the pipe device */ - - ret = register_driver(devname, &pipe_fops, 0666, (void*)dev); - if (ret != 0) - { - (void)sem_post(&g_pipesem); - err = -ret; - goto errout_with_dev; - } - - /* Remember that we created this device */ - - g_pipecreated |= (1 << pipeno); - } - - (void)sem_post(&g_pipesem); - - /* Get a write file descriptor */ - - filedes[1] = open(devname, O_WRONLY); - if (filedes[1] < 0) - { - err = -filedes[1]; - goto errout_with_driver; - } - - /* Get a read file descriptor */ - - filedes[0] = open(devname, O_RDONLY); - if (filedes[0] < 0) - { - err = -filedes[0]; - goto errout_with_wrfd; - } - - return OK; - -errout_with_wrfd: - close(filedes[1]); -errout_with_driver: - unregister_driver(devname); -errout_with_dev: - pipecommon_freedev(dev); -errout_with_pipe: - pipe_free(pipeno); -errout: - errno = err; - return ERROR; -} - -#endif /* CONFIG_DEV_PIPE_SIZE > 0 */ diff --git a/nuttx/drivers/pipes/pipe_common.c b/nuttx/drivers/pipes/pipe_common.c deleted file mode 100644 index 5f61fdd8e..000000000 --- a/nuttx/drivers/pipes/pipe_common.c +++ /dev/null @@ -1,682 +0,0 @@ -/**************************************************************************** - * drivers/pipes/pipe_common.c - * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#if CONFIG_DEBUG -# include -#endif - -#include "pipe_common.h" - -#if CONFIG_DEV_PIPE_SIZE > 0 - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* CONFIG_DEV_PIPEDUMP will dump the contents of each transfer into and out - * of the pipe. - */ - -#ifdef CONFIG_DEV_PIPEDUMP -# define pipe_dumpbuffer(m,a,n) lib_dumpbuffer(m,a,n) -#else -# define pipe_dumpbuffer(m,a,n) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void pipecommon_semtake(sem_t *sem); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pipecommon_semtake - ****************************************************************************/ - -static void pipecommon_semtake(sem_t *sem) -{ - while (sem_wait(sem) != 0) - { - /* The only case that an error should occur here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -/**************************************************************************** - * Name: pipecommon_pollnotify - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static void pipecommon_pollnotify(FAR struct pipe_dev_s *dev, pollevent_t eventset) -{ - int i; - - for (i = 0; i < CONFIG_DEV_PIPE_NPOLLWAITERS; i++) - { - struct pollfd *fds = dev->d_fds[i]; - if (fds) - { - fds->revents |= (fds->events & eventset); - if (fds->revents != 0) - { - fvdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } - } -} -#else -# define pipecommon_pollnotify(dev,event) -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pipecommon_allocdev - ****************************************************************************/ - -FAR struct pipe_dev_s *pipecommon_allocdev(void) -{ - struct pipe_dev_s *dev; - - /* Allocate a private structure to manage the pipe */ - - dev = (struct pipe_dev_s *)kmalloc(sizeof(struct pipe_dev_s)); - if (dev) - { - /* Initialize the private structure */ - - memset(dev, 0, sizeof(struct pipe_dev_s)); - sem_init(&dev->d_bfsem, 0, 1); - sem_init(&dev->d_rdsem, 0, 0); - sem_init(&dev->d_wrsem, 0, 0); - } - - return dev; -} - -/**************************************************************************** - * Name: pipecommon_freedev - ****************************************************************************/ - -void pipecommon_freedev(FAR struct pipe_dev_s *dev) -{ - sem_destroy(&dev->d_bfsem); - sem_destroy(&dev->d_rdsem); - sem_destroy(&dev->d_wrsem); - kfree(dev); -} - -/**************************************************************************** - * Name: pipecommon_open - ****************************************************************************/ - -int pipecommon_open(FAR struct file *filep) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; - int sval; - int ret; - - /* Some sanity checking */ -#if CONFIG_DEBUG - if (!dev) - { - return -EBADF; - } -#endif - - /* Make sure that we have exclusive access to the device structure. The - * sem_wait() call should fail only if we are awakened by a signal. - */ - - ret = sem_wait(&dev->d_bfsem); - if (ret != OK) - { - fdbg("sem_wait failed: %d\n", errno); - DEBUGASSERT(errno > 0); - return -errno; - } - - /* If this the first reference on the device, then allocate the buffer */ - - if (dev->d_refs == 0) - { - dev->d_buffer = (uint8_t*)kmalloc(CONFIG_DEV_PIPE_SIZE); - if (!dev->d_buffer) - { - (void)sem_post(&dev->d_bfsem); - return -ENOMEM; - } - } - - /* Increment the reference count on the pipe instance */ - - dev->d_refs++; - - /* If opened for writing, increment the count of writers on on the pipe instance */ - - if ((filep->f_oflags & O_WROK) != 0) - { - dev->d_nwriters++; - - /* If this this is the first writer, then the read semaphore indicates the - * number of readers waiting for the first writer. Wake them all up. - */ - - if (dev->d_nwriters == 1) - { - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - } - } - - /* If opened for read-only, then wait for at least one writer on the pipe */ - - sched_lock(); - (void)sem_post(&dev->d_bfsem); - if ((filep->f_oflags & O_RDWR) == O_RDONLY && dev->d_nwriters < 1) - { - /* NOTE: d_rdsem is normally used when the read logic waits for more - * data to be written. But until the first writer has opened the - * pipe, the meaning is different: it is used prevent O_RDONLY open - * calls from returning until there is at least one writer on the pipe. - * This is required both by spec and also because it prevents - * subsequent read() calls from returning end-of-file because there is - * no writer on the pipe. - */ - - ret = sem_wait(&dev->d_rdsem); - if (ret != OK) - { - /* The sem_wait() call should fail only if we are awakened by - * a signal. - */ - - fdbg("sem_wait failed: %d\n", errno); - DEBUGASSERT(errno > 0); - ret = -errno; - - /* Immediately close the pipe that we just opened */ - - (void)pipecommon_close(filep); - } - } - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: pipecommon_close - ****************************************************************************/ - -int pipecommon_close(FAR struct file *filep) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; - int sval; - - /* Some sanity checking */ -#if CONFIG_DEBUG - if (!dev) - { - return -EBADF; - } -#endif - - /* Make sure that we have exclusive access to the device structure. - * NOTE: close() is supposed to return EINTR if interrupted, however - * I've never seen anyone check that. - */ - - pipecommon_semtake(&dev->d_bfsem); - - /* Check if the decremented reference count would go to zero */ - - if (dev->d_refs > 1) - { - /* No.. then just decrement the reference count */ - - dev->d_refs--; - - /* If opened for writing, decrement the count of writers on on the pipe instance */ - - if ((filep->f_oflags & O_WROK) != 0) - { - /* If there are no longer any writers on the pipe, then notify all of the - * waiting readers that they must return end-of-file. - */ - - if (--dev->d_nwriters <= 0) - { - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - } - } - } - else - { - /* Yes... deallocate the buffer */ - - kfree(dev->d_buffer); - dev->d_buffer = NULL; - - /* And reset all counts and indices */ - - dev->d_wrndx = 0; - dev->d_rdndx = 0; - dev->d_refs = 0; - dev->d_nwriters = 0; - } - - sem_post(&dev->d_bfsem); - return OK; -} - -/**************************************************************************** - * Name: pipecommon_read - ****************************************************************************/ - -ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; -#ifdef CONFIG_DEV_PIPEDUMP - FAR uint8_t *start = (uint8_t*)buffer; -#endif - ssize_t nread = 0; - int sval; - int ret; - - /* Some sanity checking */ -#if CONFIG_DEBUG - if (!dev) - { - return -ENODEV; - } -#endif - - /* Make sure that we have exclusive access to the device structure */ - - if (sem_wait(&dev->d_bfsem) < 0) - { - return ERROR; - } - - /* If the pipe is empty, then wait for something to be written to it */ - - while (dev->d_wrndx == dev->d_rdndx) - { - /* If O_NONBLOCK was set, then return EGAIN */ - - if (filep->f_oflags & O_NONBLOCK) - { - sem_post(&dev->d_bfsem); - return -EAGAIN; - } - - /* If there are no writers on the pipe, then return end of file */ - - if (dev->d_nwriters <= 0) - { - sem_post(&dev->d_bfsem); - return 0; - } - - /* Otherwise, wait for something to be written to the pipe */ - - sched_lock(); - sem_post(&dev->d_bfsem); - ret = sem_wait(&dev->d_rdsem); - sched_unlock(); - - if (ret < 0 || sem_wait(&dev->d_bfsem) < 0) - { - return ERROR; - } - } - - /* Then return whatever is available in the pipe (which is at least one byte) */ - - nread = 0; - while (nread < len && dev->d_wrndx != dev->d_rdndx) - { - *buffer++ = dev->d_buffer[dev->d_rdndx]; - if (++dev->d_rdndx >= CONFIG_DEV_PIPE_SIZE) - { - dev->d_rdndx = 0; - } - nread++; - } - - /* Notify all waiting writers that bytes have been removed from the buffer */ - - while (sem_getvalue(&dev->d_wrsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_wrsem); - } - - /* Notify all poll/select waiters that they can write to the FIFO */ - - pipecommon_pollnotify(dev, POLLOUT); - - sem_post(&dev->d_bfsem); - pipe_dumpbuffer("From PIPE:", start, nread); - return nread; -} - -/**************************************************************************** - * Name: pipecommon_write - ****************************************************************************/ - -ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer, size_t len) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; - ssize_t nwritten = 0; - ssize_t last; - int nxtwrndx; - int sval; - - /* Some sanity checking */ - -#if CONFIG_DEBUG - if (!dev) - { - return -ENODEV; - } -#endif - - pipe_dumpbuffer("To PIPE:", (uint8_t*)buffer, len); - - /* At present, this method cannot be called from interrupt handlers. That is - * because it calls sem_wait (via pipecommon_semtake below) and sem_wait cannot - * be called from interrupt level. This actually happens fairly commonly - * IF dbg() is called from interrupt handlers and stdout is being redirected - * via a pipe. In that case, the debug output will try to go out the pipe - * (interrupt handlers should use the lldbg() APIs). - * - * On the other hand, it would be very valuable to be able to feed the pipe - * from an interrupt handler! TODO: Consider disabling interrupts instead - * of taking semaphores so that pipes can be written from interupt handlers - */ - - DEBUGASSERT(up_interrupt_context() == false) - - /* Make sure that we have exclusive access to the device structure */ - - if (sem_wait(&dev->d_bfsem) < 0) - { - return ERROR; - } - - /* Loop until all of the bytes have been written */ - - last = 0; - for (;;) - { - /* Calculate the write index AFTER the next byte is written */ - - nxtwrndx = dev->d_wrndx + 1; - if (nxtwrndx >= CONFIG_DEV_PIPE_SIZE) - { - nxtwrndx = 0; - } - - /* Would the next write overflow the circular buffer? */ - - if (nxtwrndx != dev->d_rdndx) - { - /* No... copy the byte */ - - dev->d_buffer[dev->d_wrndx] = *buffer++; - dev->d_wrndx = nxtwrndx; - - /* Is the write complete? */ - - if (++nwritten >= len) - { - /* Yes.. Notify all of the waiting readers that more data is available */ - - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - - /* Notify all poll/select waiters that they can write to the FIFO */ - - pipecommon_pollnotify(dev, POLLIN); - - /* Return the number of bytes written */ - - sem_post(&dev->d_bfsem); - return len; - } - } - else - { - /* There is not enough room for the next byte. Was anything written in this pass? */ - - if (last < nwritten) - { - /* Yes.. Notify all of the waiting readers that more data is available */ - - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - } - last = nwritten; - - /* If O_NONBLOCK was set, then return partial bytes written or EGAIN */ - - if (filep->f_oflags & O_NONBLOCK) - { - if (nwritten == 0) - { - nwritten = -EAGAIN; - } - sem_post(&dev->d_bfsem); - return nwritten; - } - - /* There is more to be written.. wait for data to be removed from the pipe */ - - sched_lock(); - sem_post(&dev->d_bfsem); - pipecommon_semtake(&dev->d_wrsem); - sched_unlock(); - pipecommon_semtake(&dev->d_bfsem); - } - } -} - -/**************************************************************************** - * Name: pipecommon_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct pipe_dev_s *dev = inode->i_private; - pollevent_t eventset; - pipe_ndx_t nbytes; - int ret = OK; - int i; - - /* Some sanity checking */ - -#if CONFIG_DEBUG - if (!dev || !fds) - { - return -ENODEV; - } -#endif - - /* Are we setting up the poll? Or tearing it down? */ - - pipecommon_semtake(&dev->d_bfsem); - if (setup) - { - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_DEV_PIPE_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!dev->d_fds[i]) - { - /* Bind the poll structure and this slot */ - - dev->d_fds[i] = fds; - fds->priv = &dev->d_fds[i]; - break; - } - } - - if (i >= CONFIG_DEV_PIPE_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should immediately notify on any of the requested events? - * First, determine how many bytes are in the buffer - */ - - if (dev->d_wrndx >= dev->d_rdndx) - { - nbytes = dev->d_wrndx - dev->d_rdndx; - } - else - { - nbytes = (CONFIG_DEV_PIPE_SIZE-1) + dev->d_wrndx - dev->d_rdndx; - } - - /* Notify the POLLOUT event if the pipe is not full */ - - eventset = 0; - if (nbytes < (CONFIG_DEV_PIPE_SIZE-1)) - { - eventset |= POLLOUT; - } - - /* Notify the POLLIN event if the pipe is not empty */ - - if (nbytes > 0) - { - eventset |= POLLIN; - } - - if (eventset) - { - pipecommon_pollnotify(dev, eventset); - } - } - else - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - -#ifdef CONFIG_DEBUG - if (!slot) - { - ret = -EIO; - goto errout; - } -#endif - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&dev->d_bfsem); - return ret; -} -#endif - -#endif /* CONFIG_DEV_PIPE_SIZE > 0 */ diff --git a/nuttx/drivers/pipes/pipe_common.h b/nuttx/drivers/pipes/pipe_common.h deleted file mode 100644 index 44822e07f..000000000 --- a/nuttx/drivers/pipes/pipe_common.h +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** - * drivers/pipe/pipe_common.h - * - * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_PIPES_PIPE_COMMON_H -#define __DRIVERS_PIPES_PIPE_COMMON_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include - -#include -#include -#include - -#ifndef CONFIG_DEV_PIPE_SIZE -# define CONFIG_DEV_PIPE_SIZE 1024 -#endif - -#if CONFIG_DEV_PIPE_SIZE > 0 - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Maximum number of threads than can be waiting for POLL events */ - -#ifndef CONFIG_DEV_PIPE_NPOLLWAITERS -# define CONFIG_DEV_PIPE_NPOLLWAITERS 2 -#endif - -/* Maximum number of open's supported on pipe */ - -#define CONFIG_DEV_PIPE_MAXUSER 255 - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/* Make the buffer index as small as possible for the configured pipe size */ - -#if CONFIG_DEV_PIPE_SIZE > 65535 -typedef uint32_t pipe_ndx_t; /* 32-bit index */ -#elif CONFIG_DEV_PIPE_SIZE > 255 -typedef uint16_t pipe_ndx_t; /* 16-bit index */ -#else -typedef uint8_t pipe_ndx_t; /* 8-bit index */ -#endif - -/* This structure represents the state of one pipe. A reference to this - * structure is retained in the i_private field of the inode whenthe pipe/fifo - * device is registered. - */ - -struct pipe_dev_s -{ - sem_t d_bfsem; /* Used to serialize access to d_buffer and indices */ - sem_t d_rdsem; /* Empty buffer - Reader waits for data write */ - sem_t d_wrsem; /* Full buffer - Writer waits for data read */ - pipe_ndx_t d_wrndx; /* Index in d_buffer to save next byte written */ - pipe_ndx_t d_rdndx; /* Index in d_buffer to return the next byte read */ - uint8_t d_refs; /* References counts on pipe (limited to 255) */ - uint8_t d_nwriters; /* Number of reference counts for write access */ - uint8_t d_pipeno; /* Pipe minor number */ - uint8_t *d_buffer; /* Buffer allocated when device opened */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *d_fds[CONFIG_DEV_PIPE_NPOLLWAITERS]; -#endif -}; - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -#ifdef __cplusplus -# define EXTERN extern "C" -extern "C" { -#else -# define EXTERN extern -#endif - -EXTERN FAR struct pipe_dev_s *pipecommon_allocdev(void); -EXTERN void pipecommon_freedev(FAR struct pipe_dev_s *dev); -EXTERN int pipecommon_open(FAR struct file *filep); -EXTERN int pipecommon_close(FAR struct file *filep); -EXTERN ssize_t pipecommon_read(FAR struct file *, FAR char *, size_t); -EXTERN ssize_t pipecommon_write(FAR struct file *, FAR const char *, size_t); -#ifndef CONFIG_DISABLE_POLL -EXTERN int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup); -#endif - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* CONFIG_DEV_PIPE_SIZE > 0 */ -#endif /* __DRIVERS_PIPES_PIPE_COMMON_H */ diff --git a/nuttx/drivers/power/Kconfig b/nuttx/drivers/power/Kconfig deleted file mode 100644 index ac76331b6..000000000 --- a/nuttx/drivers/power/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# -config BATTERY - bool "Battery support" - default n - -config MAX1704X - bool "MAX1704X Battery charger support" - default n - select I2C - select I2C_MAX1704X - depends on BATTERY - ---help--- - The MAX17040/MAX17041 are ultra-compact, low-cost, host-side fuel-gauge - systems for lithium-ion (Li+) batteries in handheld and portable equipment. - The MAX17040 is configured to operate with a single lithium cell and the - MAX17041 is configured for a dual-cell 2S pack. - -config I2C_MAX1704X - bool - default y if MAX1704X diff --git a/nuttx/drivers/power/Make.defs b/nuttx/drivers/power/Make.defs deleted file mode 100644 index e3452120d..000000000 --- a/nuttx/drivers/power/Make.defs +++ /dev/null @@ -1,84 +0,0 @@ -############################################################################ -# drivers/power/Make.defs -# -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -POWER_DEPPATH = -POWER_VPATH = -POWER_CFLAGS = - -# Include power management sources - -ifeq ($(CONFIG_PM),y) - -CSRCS += pm_activity.c pm_changestate.c pm_checkstate.c pm_initialize.c pm_register.c pm_update.c - -# Include power management in the build - -POWER_DEPPATH := --dep-path power -POWER_VPATH := :power -POWER_CFLAGS := ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power} - -endif - -# Add battery drivers - -ifeq ($(CONFIG_BATTERY),y) - -CSRCS += battery.c - -# Add I2C-based battery drivers - -ifeq ($(CONFIG_I2C),y) - -# Add the MAX1704x I2C-based battery driver - -ifeq ($(CONFIG_I2C_MAX1704X),y) -CSRCS += max1704x.c -endif - -endif - -# Include battery suport in the build - -POWER_DEPPATH := --dep-path power -POWER_VPATH := :power -POWER_CFLAGS := ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power} - -endif - -# Include power management in the build - -DEPPATH += $(POWER_DEPPATH) -VPATH += $(POWER_VPATH) -CFLAGS += $(POWER_CFLAGS) diff --git a/nuttx/drivers/power/battery.c b/nuttx/drivers/power/battery.c deleted file mode 100644 index 698e5571b..000000000 --- a/nuttx/drivers/power/battery.c +++ /dev/null @@ -1,254 +0,0 @@ -/**************************************************************************** - * drivers/power/battery.c - * Upper-half, character driver for batteries. - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include -#include - -/* This driver requires: - * - * CONFIG_BATTERY - Upper half battery driver support - */ - -#if defined(CONFIG_BATTERY) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Character driver methods */ - -static int bat_open(FAR struct file *filep); -static int bat_close(FAR struct file *filep); -static ssize_t bat_read(FAR struct file *, FAR char *, size_t nbytes); -static ssize_t bat_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static int bat_ioctl(FAR struct file *filep,int cmd,unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations g_batteryops = -{ - bat_open, - bat_close, - bat_read, - bat_write, - 0, - bat_ioctl -#ifndef CONFIG_DISABLE_POLL - , 0 -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ -/**************************************************************************** - * Name: bat_open - * - * Description: - * This function is called whenever the battery device is opened. - * - ****************************************************************************/ - -static int bat_open(FAR struct file *filep) -{ - return OK; -} - -/**************************************************************************** - * Name: bat_close - * - * Description: - * This routine is called when the battery device is closed. - * - ****************************************************************************/ - -static int bat_close(FAR struct file *filep) -{ - return OK; -} - -/**************************************************************************** - * Name: bat_read - ****************************************************************************/ - -static ssize_t bat_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - /* Return nothing read */ - - return 0; -} - -/**************************************************************************** - * Name: bat_write - ****************************************************************************/ - -static ssize_t bat_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen) -{ - /* Return nothing written */ - - return 0; -} - -/**************************************************************************** - * Name: bat_ioctl - ****************************************************************************/ - -static int bat_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct battery_dev_s *dev = inode->i_private; - int ret = -EINVAL; - - /* Inforce mutually exclusive access to the battery driver */ - - ret = sem_wait(&dev->batsem); - if (ret < 0) - { - return -errno; /* Probably EINTR */ - } - - /* Procss the IOCTL command */ - - ret = -EINVAL; /* Assume a bad argument */ - switch (cmd) - { - case BATIOC_STATE: - { - FAR int *ptr = (FAR int *)((uintptr_t)arg); - if (ptr) - { - ret = dev->ops->state(dev, ptr); - } - } - break; - - case BATIOC_ONLINE: - { - FAR bool *ptr = (FAR bool *)((uintptr_t)arg); - if (ptr) - { - ret = dev->ops->online(dev, ptr); - } - } - break; - - case BATIOC_VOLTAGE: - { - FAR b16_t *ptr = (FAR b16_t *)((uintptr_t)arg); - if (ptr) - { - ret = dev->ops->voltage(dev, ptr); - } - } - break; - - case BATIOC_CAPACITY: - { - FAR b16_t *ptr = (FAR b16_t *)((uintptr_t)arg); - if (ptr) - { - ret = dev->ops->capacity(dev, ptr); - } - } - break; - - default: - dbg("Unrecognized cmd: %d\n", cmd); - ret = -ENOTTY; - break; - } - - sem_post(&dev->batsem); - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: battery_register - * - * Description: - * Register a lower half battery driver with the common, upper-half - * battery driver. - * - * Input parameters: - * devpath - The location in the pseudo-filesystem to create the driver. - * Recommended standard is "/dev/bat0", "/dev/bat1", etc. - * dev - An instance of the battery state structure . - * - * Returned value: - * Zero on success or a negated errno value on failure. - * - ****************************************************************************/ - -int battery_register(FAR const char *devpath, FAR struct battery_dev_s *dev) -{ - int ret; - - /* Register the character driver */ - - ret = register_driver(devpath, &g_batteryops, 0555, dev); - if (ret < 0) - { - dbg("Failed to register driver: %d\n", ret); - } - return ret; -} -#endif /* CONFIG_BATTERY */ diff --git a/nuttx/drivers/power/max1704x.c b/nuttx/drivers/power/max1704x.c deleted file mode 100644 index ec50515e6..000000000 --- a/nuttx/drivers/power/max1704x.c +++ /dev/null @@ -1,564 +0,0 @@ -/**************************************************************************** - * drivers/power/max1704x.c - * Lower half driver for MAX1704x battery charger - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/* "The MAX17040/MAX17041 are ultra-compact, low-cost, host-side fuel-gauge - * systems for lithium-ion (Li+) batteries in handheld and portable equipment. - * The MAX17040 is configured to operate with a single lithium cell and the - * MAX17041 is configured for a dual-cell 2S pack. - */ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include - -/* This driver requires: - * - * CONFIG_BATTERY - Upper half battery driver support - * CONFIG_I2C - I2C support - * CONFIG_I2C_MAX1704X - And the driver must be explictly selected. - */ - -#if defined(CONFIG_BATTERY) && defined(CONFIG_I2C) && defined(CONFIG_I2C_MAX1704X) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* CONFIG_I2C_MAX17040 or CONFIG_I2C_MAX17041 - The driver must know which - * chip is on the board in order to scale the voltage correctly. - */ - -#if !defined(CONFIG_I2C_MAX17040) && !defined(CONFIG_I2C_MAX17041) -# warning "Assuming CONFIG_I2C_MAX17040" -# define CONFIG_I2C_MAX17040 1 -#endif - -/* MAX1704x Register Definitions ********************************************/ -/* "All host interaction with the MAX17040/MAX17041 is handled by writing to - * and reading from register locations. The MAX17040/MAX17041 have six 16-bit - * registers: SOC, VCELL, MODE, VERSION, RCOMP, and COMMAND. Register reads - * and writes are only valid if all 16 bits are transferred..." - */ - -/* "VCELL Register. Battery voltage is measured at the CELL pin input with - * respect to GND over a 0 to 5.00V range for the MAX17040 and 0 to 10.00V - * for the MAX17041 with resolutions of 1.25mV and 2.50mV, respectively..." - */ - -#define MAX1407X_VCELL_ADDR 0x02 /* Bits 4-15: Bits 0-11 of the battery voltage */ - -/* VCELL conversion macros */ - -#define MAX14700_VCELL_CONV 82 /* 0.00125 v * 65536 */ -#define MAX14070_VCELL(v) ((b16_t)(v) * MAX14700_VCELL_CONV) - -#define MAX14701_VCELL_CONV 163 /* 0.0025 v * 65536 */ -#define MAX14071_VCELL(v) ((b16_t)(v) * MAX14701_VCELL_CONV) - -#ifdef CONFIG_I2C_MAX17040 -# define MAX1407X_VCELL(v) MAX14070_VCELL(v) -#else -# define MAX1407X_VCELL(v) MAX14071_VCELL(v) -#endif - -/* "SOC Register. The SOC register is a read-only register that displays the - * state of charge of the cell as calculated by the ModelGauge algorithm. The - * result is displayed as a percentage of the cell’s full capacity... - * - * "...Units of % can be directly determined by observing only the high byte - * of the SOC register. The low byte provides additional resolution in units - * 1/256%. - */ - -#define MAX1407X_SOC_ADDR 0x04 /* Bits 0-15: Full SOC */ - -/* SoC conversion macros */ - -#define MAX1407X_SOC(s) ((b16_t)(s) << 8) -#define MAX17040_SOC_FULL itob16(95) /* We say full if Soc >= 95% */ - -/* "MODE Register.The MODE register allows the host processor to send special - * commands to the IC." - */ - -#define MAX1407X_MODE_ADDR 0x06 /* Bits 0-15: 16-bit MODE */ - -/* Supported modes */ - -#define MAX1407X_MODE_QUICKSTART 0x4000 - -/* "The VERSION register is a read-only register that contains a value - * indicating the production version of the MAX17040/MAX17041." - */ - -#define MAX1407X_VERSION_ADDR 0x08 /* Bits 0-15: 16-bit VERSION */ - -/* "RCOMP Register. RCOMP is a 16-bit value used to compensate the ModelGauge - * algorithm. RCOMP can be adjusted to optimize performance for different - * lithium chemistries or different operating temperatures... The factory- - * default value for RCOMP is 9700h." - */ - -#define MAX1407X_RCOMP_ADDR 0x0c /* Bits 0-15: 16-bit RCOMP */ - -/* "COMMAND Register. The COMMAND register allows the host processor to send - * special commands to the IC..." - */ - -#define MAX1407X_COMMAND_ADDR 0xfe /* Bits 0-7: 16-bit COMMAND */ - -/* Supported copmmands */ - -#define MAX1407X_COMMAND_POR 0x5400 - -/* Debug ********************************************************************/ - -#ifdef CONFIG_DEBUG_MAX1704X -# define batdbg dbg -#else -# ifdef CONFIG_CPP_HAVE_VARARGS -# define batdbg(x...) -# else -# define batdbg (void) -# endif -#endif - -/**************************************************************************** - * Private - ****************************************************************************/ - -struct max1704x_dev_s -{ - /* The common part of the battery driver visible to the upper-half driver */ - - FAR const struct battery_operations_s *ops; /* Battery operations */ - sem_t batsem; /* Enforce mutually exclusive access */ - - /* Data fields specific to the lower half MAX1704x driver follow */ - - FAR struct i2c_dev_s *i2c; /* I2C interface */ - uint8_t addr; /* I2C address */ - uint32_t frequency; /* I2C frequency */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* I2C support */ - -static int max1704x_getreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr, - FAR uint16_t *regval); -static int max1704x_putreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr, - uint16_t regval); - -static inline int max1704x_getvcell(FAR struct max1704x_dev_s *priv, - b16_t *vcell); -static inline int max1704x_getsoc(FAR struct max1704x_dev_s *priv, - b16_t *soc); -static inline int max1704x_setquikstart(FAR struct max1704x_dev_s *priv); -static inline int max1704x_getversion(FAR struct max1704x_dev_s *priv, - uint16_t *version); -static inline int max1704x_reset(FAR struct max1704x_dev_s *priv); - -/* Battery driver lower half methods */ - -static int max1704x_state(struct battery_dev_s *dev, int *status); -static int max1704x_online(struct battery_dev_s *dev, bool *status); -static int max1704x_voltage(struct battery_dev_s *dev, b16_t *value); -static int max1704x_capacity(struct battery_dev_s *dev, b16_t *value); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct battery_operations_s g_max1704xops = -{ - max1704x_state, - max1704x_online, - max1704x_voltage, - max1704x_capacity -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: max1704x_getreg16 - * - * Description: - * Read a 16-bit value from a MAX1704x register pair. - * - * START ACK ACK - * REPEATED-START ACK Data0 ACK Data1 NO-ACK STOP - * - ****************************************************************************/ - -static int max1704x_getreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr, - FAR uint16_t *regval) -{ - uint8_t buffer[2]; - int ret; - - /* Set the I2C address and address size */ - - I2C_SETADDRESS(priv->i2c, priv->addr, 7); - - /* Write the register address */ - - ret = I2C_WRITE(priv->i2c, ®addr, 1); - if (ret < 0) - { - batdbg("I2C_WRITE failed: %d\n", ret); - return ret; - } - - /* Restart and read 16-bits from the register */ - - ret = I2C_READ(priv->i2c, buffer, 2); - if (ret < 0) - { - batdbg("I2C_READ failed: %d\n", ret); - return ret; - } - - /* Return the 16-bit value */ - - return (uint16_t)buffer[0] << 8 | (uint16_t)buffer[1]; - return OK; -} - -/**************************************************************************** - * Name: max1704x_putreg16 - * - * Description: - * Write a 16-bit value to a MAX1704x register pair. - * - * START ACK ACK Data0 ACK Data1 ACK STOP - * - ****************************************************************************/ - -static int max1704x_putreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr, - uint16_t regval) -{ - uint8_t buffer[3]; - - batdbg("addr: %02x regval: %08x\n", regaddr, regval); - - /* Set up a 3 byte message to send */ - - buffer[0] = regaddr; - buffer[1] = (uint8_t)(regval >> 8); - buffer[2] = (uint8_t)(regval & 0xff); - - /* Set the I2C address and address size */ - - I2C_SETADDRESS(priv->i2c, priv->addr, 7); - - /* Write the register address followed by the data (no RESTART) */ - - return I2C_WRITE(priv->i2c, buffer, 3); -} - -/**************************************************************************** - * Name: max1704x_getvcell - * - * Description: - * Read the VCELL register and scale the returned value - * - ****************************************************************************/ - -static inline int max1704x_getvcell(FAR struct max1704x_dev_s *priv, - b16_t *vcell) -{ - uint16_t regval = 0; - int ret; - - ret = max1704x_getreg16(priv, MAX1407X_VCELL_ADDR, ®val); - if (ret == OK) - { - *vcell = MAX1407X_VCELL(regval); - } - return ret; -} - -/**************************************************************************** - * Name: max1704x_getsoc - * - * Description: - * Read the SOC register and scale the returned value - * - ****************************************************************************/ - -static inline int max1704x_getsoc(FAR struct max1704x_dev_s *priv, - b16_t *soc) -{ - uint16_t regval = 0; - int ret; - - ret = max1704x_getreg16(priv, MAX1407X_VCELL_ADDR, ®val); - if (ret == OK) - { - *soc = MAX1407X_SOC(regval); - } - return ret; -} - -/**************************************************************************** - * Name: max1704x_setquikstart - * - * Description: - * Set Quickstart mode - * - ****************************************************************************/ - -static inline int max1704x_setquikstart(FAR struct max1704x_dev_s *priv) -{ - return max1704x_putreg16(priv, MAX1407X_MODE_ADDR, MAX1407X_MODE_QUICKSTART); -} - -/**************************************************************************** - * Name: max1704x_getversion - * - * Description: - * Read the SOC register and scale the returned value - * - ****************************************************************************/ - -static inline int max1704x_getversion(FAR struct max1704x_dev_s *priv, - uint16_t *version) -{ - return max1704x_getreg16(priv, MAX1407X_VCELL_ADDR, version); -} - -/**************************************************************************** - * Name: max1704x_setrcomp - * - * Description: - * Set Quickstart mode - * - ****************************************************************************/ - -static inline int max1704x_setrcomp(FAR struct max1704x_dev_s *priv, uint16_t rcomp) -{ - return max1704x_putreg16(priv, MAX1407X_RCOMP_ADDR, rcomp); -} - -/**************************************************************************** - * Name: max1704x_reset - * - * Description: - * Reset the MAX1704x - * - ****************************************************************************/ - -static inline int max1704x_reset(FAR struct max1704x_dev_s *priv) -{ - return max1704x_putreg16(priv, MAX1407X_COMMAND_ADDR, MAX1407X_COMMAND_POR); -} - -/**************************************************************************** - * Name: max1704x_state - * - * Description: - * Return the current battery state - * - ****************************************************************************/ - -static int max1704x_state(struct battery_dev_s *dev, int *status) -{ - FAR struct max1704x_dev_s *priv = (FAR struct max1704x_dev_s *)dev; - b16_t soc = 0; - int ret; - - /* Only a few of the possible battery states are supported by this driver: - * - * BATTERY_UNKNOWN - Returned on error conditions - * BATTERY_IDLE - This is what will usually be reported - * BATTERY_FULL - This will be reported if the SoC is greater than 95% - * BATTERY_CHARGING and BATTERY_DISCHARGING - I don't think this hardware - * knows anything about current (charging or dischargin). - */ - - ret = max1704x_getsoc(priv, &soc); - if (ret < 0) - { - *status = BATTERY_UNKNOWN; - return ret; - } - - /* Is the battery fully charged? */ - - if (soc > MAX17040_SOC_FULL) - { - *status = BATTERY_FULL; - } - else - { - *status = BATTERY_IDLE; - } - - return OK; -} - -/**************************************************************************** - * Name: max1704x_online - * - * Description: - * Return true if the batter is online - * - ****************************************************************************/ - -static int max1704x_online(struct battery_dev_s *dev, bool *status) -{ - /* There is no concept of online/offline in this driver */ - - *status = true; - return OK; -} - -/**************************************************************************** - * Name: max1704x_voltage - * - * Description: - * Current battery voltage - * - ****************************************************************************/ - -static int max1704x_voltage(struct battery_dev_s *dev, b16_t *value) -{ - FAR struct max1704x_dev_s *priv = (FAR struct max1704x_dev_s *)dev; - return max1704x_getvcell(priv, value); -} - -/**************************************************************************** - * Name: max1704x_capacity - * - * Description: - * Battery capacity - * - ****************************************************************************/ - -static int max1704x_capacity(struct battery_dev_s *dev, b16_t *value) -{ - FAR struct max1704x_dev_s *priv = (FAR struct max1704x_dev_s *)dev; - return max1704x_getsoc(priv, value); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: max1704x_initialize - * - * Description: - * Initialize the MAX1704x battery driver and return an instance of the - * lower_half interface that may be used with battery_register(); - * - * This driver requires: - * - * CONFIG_BATTERY - Upper half battery driver support - * CONFIG_I2C - I2C support - * CONFIG_I2C_MAX1704X - And the driver must be explictly selected. - * CONFIG_I2C_MAX17040 or CONFIG_I2C_MAX17041 - The driver must know which - * chip is on the board in order to scale the voltage correctly. - * - * Input Parameters: - * i2c - An instance of the I2C interface to use to communicate with the MAX1704x - * addr - The I2C address of the MAX1704x (Better be 0x36). - * frequency - The I2C frequency - * - * Returned Value: - * A pointer to the intialized lower-half driver instance. A NULL pointer - * is returned on a failure to initialize the MAX1704x lower half. - * - ****************************************************************************/ - -FAR struct battery_dev_s *max1704x_initialize(FAR struct i2c_dev_s *i2c, - uint8_t addr, uint32_t frequency) -{ - FAR struct max1704x_dev_s *priv; -#if 0 - int ret; -#endif - - /* Initialize the MAX1704x device structure */ - - priv = (FAR struct max1704x_dev_s *)kzalloc(sizeof(struct max1704x_dev_s)); - if (priv) - { - /* Initialize the MAX1704x device structure */ - - sem_init(&priv->batsem, 0, 1); - priv->ops = &g_max1704xops; - priv->i2c = i2c; - priv->addr = addr; - priv->frequency = frequency; - - /* Set the I2C frequency (ignoring the returned, actual frequency) */ - - (void)I2C_SETFREQUENCY(i2c, priv->frequency); - - /* Reset the MAX1704x (mostly just to make sure that we can talk to it) */ - -#if 0 - ret = max1704x_reset(priv); - if (ret < 0) - { - batdbg("Failed to reset the MAX1704x: %d\n", ret); - kfree(priv); - return NULL; - } -#endif - } - return (FAR struct battery_dev_s *)priv; -} - -#endif /* CONFIG_BATTERY && CONFIG_I2C && CONFIG_I2C_MAX1704X */ diff --git a/nuttx/drivers/power/pm_activity.c b/nuttx/drivers/power/pm_activity.c deleted file mode 100644 index d3c8a52e7..000000000 --- a/nuttx/drivers/power/pm_activity.c +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** - * drivers/power/pm_activity.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include "pm_internal.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_activity - * - * Description: - * This function is called by a device driver to indicate that it is - * performing meaningful activities (non-idle). This increments an activity - * count and/or will restart a idle timer and prevent entering reduced - * power states. - * - * Input Parameters: - * priority - Activity priority, range 0-9. Larger values correspond to - * higher priorities. Higher priority activity can prevent the system - * from entering reduced power states for a longer period of time. - * - * As an example, a button press might be higher priority activity because - * it means that the user is actively interacting with the device. - * - * Returned Value: - * None. - * - * Assumptions: - * This function may be called from an interrupt handler (this is the ONLY - * PM function that may be called from an interrupt handler!). - * - ****************************************************************************/ - -void pm_activity(int priority) -{ - uint32_t now; - uint32_t accum; - irqstate_t flags; - - /* Just increment the activity count in the current time slice. The priority - * is simply the number of counts that are added. - */ - - if (priority > 0) - { - /* Add the priority to the accumulated counts in a critical section. */ - - flags = irqsave(); - accum = (uint32_t)g_pmglobals.accum + priority; - - /* Make sure that we do not overflow the underlying uint16_t representation */ - - if (accum > INT16_MAX) - { - accum = INT16_MAX; - } - - /* Save the updated count */ - - g_pmglobals.accum = (int16_t)accum; - - /* Check the elapsed time. In periods of low activity, time slicing is - * controlled by IDLE loop polling; in periods of higher activity, time - * slicing is controlled by driver activity. In either case, the duration - * of the time slice is only approximate; during times of heavy activity, - * time slices may be become longer and the activity level may be over- - * estimated. - */ - - now = clock_systimer(); - if (now - g_pmglobals.stime >= TIME_SLICE_TICKS) - { - int16_t tmp; - - /* Sample the count, reset the time and count, and assess the PM - * state. This is an atomic operation because interrupts are - * still disabled. - */ - - tmp = g_pmglobals.accum; - g_pmglobals.stime = now; - g_pmglobals.accum = 0; - - /* Reassessing the PM state may require some computation. However, - * the work will actually be performed on a worker thread at a user- - * controlled priority. - */ - - (void)pm_update(accum); - } - - irqrestore(flags); - } -} - -#endif /* CONFIG_PM */ \ No newline at end of file diff --git a/nuttx/drivers/power/pm_changestate.c b/nuttx/drivers/power/pm_changestate.c deleted file mode 100644 index f64760f55..000000000 --- a/nuttx/drivers/power/pm_changestate.c +++ /dev/null @@ -1,227 +0,0 @@ -/**************************************************************************** - * drivers/power/pm_changestate.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include "pm_internal.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_prepall - * - * Description: - * Prepare every driver for the state change. - * - * Input Parameters: - * newstate - Identifies the new PM state - * - * Returned Value: - * 0 (OK) means that the callback function for all registered drivers - * returned OK (meaning that they accept the state change). Non-zero - * means that one of the drivers refused the state change. In this case, - * the system will revert to the preceding state. - * - * Assumptions: - * Interrupts are disabled. - * - ****************************************************************************/ - -static int pm_prepall(enum pm_state_e newstate) -{ - FAR sq_entry_t *entry; - int ret = OK; - - /* Visit each registered callback structure. */ - - for (entry = sq_peek(&g_pmglobals.registry); - entry && ret == OK; - entry = sq_next(entry)) - { - /* Is the prepare callback supported? */ - - FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; - if (cb->prepare) - { - /* Yes.. prepare the driver */ - - ret = cb->prepare(cb, newstate); - } - } - - return ret; -} - -/**************************************************************************** - * Name: pm_changeall - * - * Description: - * Inform all drivers of the state change. - * - * Input Parameters: - * newstate - Identifies the new PM state - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are disabled. - * - ****************************************************************************/ - -static inline void pm_changeall(enum pm_state_e newstate) -{ - FAR sq_entry_t *entry; - - /* Visit each registered callback structure. */ - - for (entry = sq_peek(&g_pmglobals.registry); entry; entry = sq_next(entry)) - { - /* Is the notification callback supported? */ - - FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; - if (cb->notify) - { - /* Yes.. notify the driver */ - - cb->notify(cb, newstate); - } - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_changestate - * - * Description: - * This function is used by platform-specific power management logic. It - * will announce the power management power management state change to all - * drivers that have registered for power management event callbacks. - * - * Input Parameters: - * newstate - Identifies the new PM state - * - * Returned Value: - * 0 (OK) means that the callback function for all registered drivers - * returned OK (meaning that they accept the state change). Non-zero - * means that one of the drivers refused the state change. In this case, - * the system will revert to the preceding state. - * - * Assumptions: - * It is assumed that interrupts are disabled when this function is - * called. This function is probably called from the IDLE loop... the - * lowest priority task in the system. Changing driver power management - * states may result in renewed system activity and, as a result, can - * suspend the IDLE thread before it completes the entire state change - * unless interrupts are disabled throughout the state change. - * - ****************************************************************************/ - -int pm_changestate(enum pm_state_e newstate) -{ - irqstate_t flags; - int ret; - - /* Disable interrupts throught this operation... changing driver states - * could cause additional driver activity that might interfere with the - * state change. When the state change is complete, interrupts will be - * re-enabled. - */ - - flags = irqsave(); - - /* First, prepare the drivers for the state change. In this phase, - * drivers may refuse the state state change. - */ - - ret = pm_prepall(newstate); - if (ret != OK) - { - /* One or more drivers is not ready for this state change. Revert to - * the preceding state. - */ - - newstate = g_pmglobals.state; - (void)pm_prepall(newstate); - } - - /* All drivers have agreed to the state change (or, one or more have - * disagreed and the state has been reverted). Set the new state. - */ - - pm_changeall(newstate); - g_pmglobals.state = newstate; - - /* Restore the interrupt state */ - - irqrestore(flags); - return ret; -} - -#endif /* CONFIG_PM */ diff --git a/nuttx/drivers/power/pm_checkstate.c b/nuttx/drivers/power/pm_checkstate.c deleted file mode 100644 index 9b0e1045e..000000000 --- a/nuttx/drivers/power/pm_checkstate.c +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** - * drivers/power/pm_checkstate.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include "pm_internal.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_checkstate - * - * Description: - * This function is called from the MCU-specific IDLE loop to monitor the - * the power management conditions. This function returns the "recommended" - * power management state based on the PM configuration and activity - * reported in the last sampling periods. The power management state is - * not automatically changed, however. The IDLE loop must call - * pm_changestate() in order to make the state change. - * - * These two steps are separated because the plaform-specific IDLE loop may - * have additional situational information that is not available to the - * the PM sub-system. For example, the IDLE loop may know that the - * battery charge level is very low and may force lower power states - * even if there is activity. - * - * NOTE: That these two steps are separated in time and, hence, the IDLE - * loop could be suspended for a long period of time between calling - * pm_checkstate() and pm_changestate(). The IDLE loop may need to make - * these calls atomic by either disabling interrupts until the state change - * is completed. - * - * Input Parameters: - * None - * - * Returned Value: - * The recommended power management state. - * - ****************************************************************************/ - -enum pm_state_e pm_checkstate(void) -{ - uint32_t now; - irqstate_t flags; - - /* Check for the end of the current time slice. This must be performed - * with interrupts disabled so that it does not conflict with the similar - * logic in pm_activity(). - */ - - flags = irqsave(); - - /* Check the elapsed time. In periods of low activity, time slicing is - * controlled by IDLE loop polling; in periods of higher activity, time - * slicing is controlled by driver activity. In either case, the duration - * of the time slice is only approximate; during times of heavy activity, - * time slices may be become longer and the activity level may be over- - * estimated. - */ - - now = clock_systimer(); - if (now - g_pmglobals.stime >= TIME_SLICE_TICKS) - { - int16_t accum; - - /* Sample the count, reset the time and count, and assess the PM - * state. This is an atomic operation because interrupts are - * still disabled. - */ - - accum = g_pmglobals.accum; - g_pmglobals.stime = now; - g_pmglobals.accum = 0; - - /* Reassessing the PM state may require some computation. However, - * the work will actually be performed on a worker thread at a user- - * controlled priority. - */ - - (void)pm_update(accum); - } - irqrestore(flags); - - /* Return the recommended state. Assuming that we are called from the - * IDLE thread at the lowest priority level, any updates scheduled on the - * worker thread above should have already been peformed and the recommended - * state should be current: - */ - - return g_pmglobals.recommended; -} - -#endif /* CONFIG_PM */ diff --git a/nuttx/drivers/power/pm_initialize.c b/nuttx/drivers/power/pm_initialize.c deleted file mode 100644 index 9401fba9e..000000000 --- a/nuttx/drivers/power/pm_initialize.c +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** - * drivers/power/pm_initialize.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include - -#include "pm_internal.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/* All PM global data: */ - -struct pm_global_s g_pmglobals; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_initialize - * - * Description: - * This function is called by MCU-specific one-time at power on reset in - * order to initialize the power management capabilities. This function - * must be called *very* early in the intialization sequence *before* any - * other device drivers are initialize (since they may attempt to register - * with the power management subsystem). - * - * Input parameters: - * None. - * - * Returned value: - * None. - * - ****************************************************************************/ - -void pm_initialize(void) -{ - /* Initialize the registry and the PM global data structures. The PM - * global data structure resides in .bss which is zeroed at boot time. So - * it is only required to initialize non-zero elements of the PM global - * data structure here. - */ - - sq_init(&g_pmglobals.registry); - sem_init(&g_pmglobals.regsem, 0, 1); -} - -#endif /* CONFIG_PM */ \ No newline at end of file diff --git a/nuttx/drivers/power/pm_internal.h b/nuttx/drivers/power/pm_internal.h deleted file mode 100644 index f98624f15..000000000 --- a/nuttx/drivers/power/pm_internal.h +++ /dev/null @@ -1,210 +0,0 @@ -/**************************************************************************** - * drivers/power/pm_internal.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_POWER_PM_INTERNAL_H -#define __DRIVERS_POWER_PM_INTERNAL_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include -#include - -#ifdef CONFIG_PM - -/**************************************************************************** - * Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ - -#ifndef CONFIG_SCHED_WORKQUEUE -# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" -#endif - -/* Convert the time slice interval into system clock ticks. - * - * CONFIG_PM_SLICEMS provides the duration of one time slice in milliseconds. - * CLOCKS_PER_SEC provides the number of timer ticks in one second. - * - * slice ticks = (CONFIG_PM_SLICEMS msec / 1000 msec/sec) / - * (CLOCKS_PER_SEC ticks/sec) - */ - -#define TIME_SLICE_TICKS ((CONFIG_PM_SLICEMS * CLOCKS_PER_SEC) / 1000) - -/* Function-like macros *****************************************************/ -/**************************************************************************** - * Name: pm_lock - * - * Descripton: - * Lock the power management registry. NOTE: This function may return - * an error if a signal is received while what (errno == EINTR). - * - ****************************************************************************/ - -#define pm_lock() sem_wait(&g_pmglobals.regsem); - -/**************************************************************************** - * Name: pm_unlock - * - * Descripton: - * Unlock the power management registry. - * - ****************************************************************************/ - -#define pm_unlock() sem_post(&g_pmglobals.regsem); - -/**************************************************************************** - * Public Types - ****************************************************************************/ -/* This structure encapsulates all of the global data used by the PM module */ - -struct pm_global_s -{ - /* state - The current state (as determined by an explicit call to - * pm_changestate() - * recommended - The recommended state based on the PM algorithm in - * function pm_update(). - * mndex - The index to the next slot in the memory[] array to use. - * mcnt - A tiny counter used only at start up. The actual - * algorithm cannot be applied until CONFIG_PM_MEMORY - * samples have been collected. - */ - - uint8_t state; - uint8_t recommended; - uint8_t mndx; - uint8_t mcnt; - - /* accum - The accumulated counts in this time interval - * thrcnt - The number of below threshold counts seen. - */ - - int16_t accum; - uint16_t thrcnt; - - /* This is the averaging "memory." The averaging algorithm is simply: - * Y = (An*X + SUM(Ai*Yi))/SUM(Aj), where i = 1..n-1 and j= 1..n, n is the - * length of the "memory", Ai is the weight applied to each value, and X is - * the current activity. - * - * CONFIG_PM_MEMORY provides the memory for the algorithm. Default: 2 - * CONFIG_PM_COEFn provides weight for each sample. Default: 1 - */ - -#if CONFIG_PM_MEMORY > 1 - int16_t memory[CONFIG_PM_MEMORY-1]; -#endif - - /* stime - The time (in ticks) at the start of the current time slice */ - - uint32_t stime; - - /* This semaphore manages mutually exclusive access to the power management - * registry. It must be initialized to the value 1. - */ - - sem_t regsem; - - /* For work that has been deferred to the worker thread */ - - struct work_s work; - - /* registry is a singly-linked list of registered power management - * callback structures. To ensure mutually exclusive access, this list - * must be locked by calling pm_lock() before it is accessed. - */ - - sq_queue_t registry; -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -# define EXTERN extern "C" -extern "C" -{ -#else -# define EXTERN extern -#endif - -/* All PM global data: */ - -EXTERN struct pm_global_s g_pmglobals; - -/************************************************************************************ - * Public Function Prototypes - ************************************************************************************/ - -/**************************************************************************** - * Name: pm_update - * - * Description: - * This internal function is called at the end of a time slice in order to - * update driver activity metrics and recommended states. - * - * Input Parameters: - * accum - The value of the activity accumulator at the end of the time - * slice. - * - * Returned Value: - * None. - * - * Assumptions: - * This function may be called from a driver, perhaps even at the interrupt - * level. It may also be called from the IDLE loop at the lowest possible - * priority level. To reconcile these various conditions, all work is - * performed on the worker thread at a user-selectable priority. - * - ****************************************************************************/ - -EXTERN void pm_update(int16_t accum); - -#undef EXTERN -#if defined(__cplusplus) -} -#endif - -#endif /* CONFIG_PM */ -#endif /* #define __DRIVERS_POWER_PM_INTERNAL_H */ diff --git a/nuttx/drivers/power/pm_register.c b/nuttx/drivers/power/pm_register.c deleted file mode 100644 index 19f94cb02..000000000 --- a/nuttx/drivers/power/pm_register.c +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** - * drivers/power/pm_register.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include - -#include "pm_internal.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_register - * - * Description: - * This function is called by a device driver in order to register to - * receive power management event callbacks. - * - * Input parameters: - * callbacks - An instance of struct pm_callback_s providing the driver - * callback functions. - * - * Returned value: - * Zero (OK) on success; otherwise a negater errno value is returned. - * - ****************************************************************************/ - -int pm_register(FAR struct pm_callback_s *callbacks) -{ - int ret; - - DEBUGASSERT(callbacks); - - /* Add the new entry to the end of the list of registered callbacks */ - - ret = pm_lock(); - if (ret == OK) - { - sq_addlast(&callbacks->entry, &g_pmglobals.registry); - pm_unlock(); - } - return ret; -} - -#endif /* CONFIG_PM */ \ No newline at end of file diff --git a/nuttx/drivers/power/pm_update.c b/nuttx/drivers/power/pm_update.c deleted file mode 100644 index 4b6b58c55..000000000 --- a/nuttx/drivers/power/pm_update.c +++ /dev/null @@ -1,334 +0,0 @@ -/**************************************************************************** - * drivers/power/pm_update.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include - -#include "pm_internal.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ -/* CONFIG_PM_MEMORY is the total number of time slices (including the current - * time slice. The histor or previous values is then CONFIG_PM_MEMORY-1. - */ - -#if CONFIG_PM_MEMORY > 1 -static const int16_t g_pmcoeffs[CONFIG_PM_MEMORY-1] = -{ - CONFIG_PM_COEF1 -#if CONFIG_PM_MEMORY > 2 - , CONFIG_PM_COEF2 -#endif -#if CONFIG_PM_MEMORY > 3 - , CONFIG_PM_COEF3 -#endif -#if CONFIG_PM_MEMORY > 4 - , CONFIG_PM_COEF4 -#endif -#if CONFIG_PM_MEMORY > 5 - , CONFIG_PM_COEF5 -#endif -#if CONFIG_PM_MEMORY > 6 -# warning "This logic needs to be extended" -#endif -}; -#endif - -/* Threshold activity values to enter into the next lower power consumption - * state. Indexing is next state 0:IDLE, 1:STANDBY, 2:SLEEP. - */ - -static const int16_t g_pmenterthresh[3] = -{ - CONFIG_PM_IDLEENTER_THRESH, - CONFIG_PM_STANDBYENTER_THRESH, - CONFIG_PM_SLEEPENTER_THRESH -}; - -/* Threshold activity values to leave the current low power consdumption - * state. Indexing is current state 0:IDLE, 1: STANDBY, 2: SLEEP. - */ - -static const int16_t g_pmexitthresh[3] = -{ - CONFIG_PM_IDLEEXIT_THRESH, - CONFIG_PM_STANDBYEXIT_THRESH, - CONFIG_PM_SLEEPEXIT_THRESH -}; - -/* Threshold time slice count to enter the next low power consdumption - * state. Indexing is next state 0:IDLE, 1: STANDBY, 2: SLEEP. - */ - -static const uint16_t g_pmcount[3] = -{ - CONFIG_PM_IDLEENTER_COUNT, - CONFIG_PM_STANDBYENTER_COUNT, - CONFIG_PM_SLEEPENTER_COUNT -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_worker - * - * Description: - * This worker function is queue at the end of a time slice in order to - * update driver activity metrics and recommended states. - * - * Input Parameters: - * arg - The value of the activity accumulator at the end of the time - * slice. - * - * Returned Value: - * None. - * - * Assumptions: - * This function runs on the worker thread. - * - ****************************************************************************/ - -void pm_worker(FAR void *arg) -{ - int16_t accum = (int16_t)((intptr_t)arg); - int32_t Y; - int index; - -#if CONFIG_PM_MEMORY > 1 - int32_t denom; - int i, j; - - /* We won't bother to do anything until we have accumulated - * CONFIG_PM_MEMORY-1 samples. - */ - - if (g_pmglobals.mcnt < CONFIG_PM_MEMORY-1) - { - g_pmglobals.memory[g_pmglobals.mcnt] = accum; - g_pmglobals.mcnt++; - return; - } - - /* The averaging algorithm is simply: Y = (An*X + SUM(Ai*Yi))/SUM(Aj), where - * i = 1..n-1 and j= 1..n, n is the length of the "memory", Ai is the - * weight applied to each value, and X is the current activity. - * - * CONFIG_PM_MEMORY provides the memory for the algorithm. Default: 2 - * CONFIG_PM_COEFn provides weight for each sample. Default: 1 - * - * First, calclate Y = An*X - */ - - Y = CONFIG_PM_COEFN * accum; - denom = CONFIG_PM_COEFN; - - /* Then calculate Y += SUM(Ai*Yi), i = 1..n-1. The oldest sample will - * reside at g_pmglobals.mndx (and this is the value that we will overwrite - * with the new value). - */ - - for (i = 0, j = g_pmglobals.mndx; i < CONFIG_PM_MEMORY-1; i++, j++) - { - if (j >= CONFIG_PM_MEMORY-1) - { - j = 0; - } - - Y += g_pmcoeffs[i] * g_pmglobals.memory[j]; - denom += g_pmcoeffs[i]; - } - - /* Compute and save the new activity value */ - - Y /= denom; - g_pmglobals.memory[g_pmglobals.mndx] = Y; - g_pmglobals.mndx++; - if (g_pmglobals.mndx >= CONFIG_PM_MEMORY-1) - { - g_pmglobals.mndx = 0; - } - -#else - - /* No smoothing */ - - Y = accum; - -#endif - - /* First check if increased activity should cause us to return to the - * normal operating state. This would be unlikely for the lowest power - * consumption states because the CPU is probably asleep. However this - * probably does apply for the IDLE state. - */ - - if (g_pmglobals.state > PM_NORMAL) - { - /* Get the table index for the current state (which will be the - * current state minus one) - */ - - index = g_pmglobals.state - 1; - - /* Has the threshold to return to normal power consumption state been - * exceeded? - */ - - if (Y > g_pmexitthresh[index]) - { - /* Yes... reset the count and recommend the normal state. */ - - g_pmglobals.thrcnt = 0; - g_pmglobals.recommended = PM_NORMAL; - return; - } - } - - /* Now, compare this new activity level to the thresholds and counts for - * the next lower power consumption state. If we are already in the SLEEP - * state, then there is nothing more to be done (in fact, I would be - * surprised to be executing!). - */ - - if (g_pmglobals.state < PM_SLEEP) - { - unsigned int nextstate; - - /* Get the next state and the table index for the next state (which will - * be the current state) - */ - - index = g_pmglobals.state; - nextstate = g_pmglobals.state + 1; - - /* Has the threshold to enter the next lower power consumption state - * been exceeded? - */ - - if (Y > g_pmenterthresh[index]) - { - /* No... reset the count and recommend the current state */ - - g_pmglobals.thrcnt = 0; - g_pmglobals.recommended = g_pmglobals.state; - } - - /* Yes.. have we already recommended this state? If so, do nothing */ - - else if (g_pmglobals.recommended < nextstate) - { - /* No.. increment the count. Has is passed the the count required - * for a state transition? - */ - - if (++g_pmglobals.thrcnt >= g_pmcount[index]) - { - /* Yes, recommend the new state and set up for the next - * transition. - */ - - g_pmglobals.thrcnt = 0; - g_pmglobals.recommended = nextstate; - } - } - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_update - * - * Description: - * This internal function is called at the end of a time slice in order to - * update driver activity metrics and recommended states. - * - * Input Parameters: - * accum - The value of the activity accumulator at the end of the time - * slice. - * - * Returned Value: - * None. - * - * Assumptions: - * This function may be called from a driver, perhaps even at the interrupt - * level. It may also be called from the IDLE loop at the lowest possible - * priority level. To reconcile these various conditions, all work is - * performed on the worker thread at a user-selectable priority. This will - * also serialize all of the updates and eliminate any need for additional - * protection. - * - ****************************************************************************/ - -void pm_update(int16_t accum) -{ - /* The work will be performed on the worker thread */ - - DEBUGASSERT(g_pmglobals.work.worker == NULL); - (void)work_queue(HPWORK, &g_pmglobals.work, pm_worker, (FAR void*)((intptr_t)accum), 0); -} - -#endif /* CONFIG_PM */ diff --git a/nuttx/drivers/pwm.c b/nuttx/drivers/pwm.c deleted file mode 100644 index 62fb4d2fb..000000000 --- a/nuttx/drivers/pwm.c +++ /dev/null @@ -1,676 +0,0 @@ -/**************************************************************************** - * drivers/pwm.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Compilation Switches - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef CONFIG_PWM - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Debug ********************************************************************/ -/* Non-standard debug that may be enabled just for testing PWM */ - -#ifdef CONFIG_DEBUG_PWM -# define pwmdbg dbg -# define pwmvdbg vdbg -# define pwmlldbg lldbg -# define pwmllvdbg llvdbg -#else -# define pwmdbg(x...) -# define pwmvdbg(x...) -# define pwmlldbg(x...) -# define pwmllvdbg(x...) -#endif - -/**************************************************************************** - * Private Type Definitions - ****************************************************************************/ - -/* This structure describes the state of the upper half driver */ - -struct pwm_upperhalf_s -{ - uint8_t crefs; /* The number of times the device has been opened */ - volatile bool started; /* True: pulsed output is being generated */ -#ifdef CONFIG_PWM_PULSECOUNT - volatile bool waiting; /* True: Caller is waiting for the pulse count to expire */ -#endif - sem_t exclsem; /* Supports mutual exclusion */ -#ifdef CONFIG_PWM_PULSECOUNT - sem_t waitsem; /* Used to wait for the pulse count to expire */ -#endif - struct pwm_info_s info; /* Pulsed output characteristics */ - FAR struct pwm_lowerhalf_s *dev; /* lower-half state */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int pwm_open(FAR struct file *filep); -static int pwm_close(FAR struct file *filep); -static ssize_t pwm_read(FAR struct file *filep, FAR char *buffer, size_t buflen); -static ssize_t pwm_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static int pwm_start(FAR struct pwm_upperhalf_s *upper, unsigned int oflags); -static int pwm_ioctl(FAR struct file *filep, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations g_pwmops = -{ - pwm_open, /* open */ - pwm_close, /* close */ - pwm_read, /* read */ - pwm_write, /* write */ - 0, /* seek */ - pwm_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/************************************************************************************ - * Name: pwm_open - * - * Description: - * This function is called whenever the PWM device is opened. - * - ************************************************************************************/ - -static int pwm_open(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct pwm_upperhalf_s *upper = inode->i_private; - uint8_t tmp; - int ret; - - pwmvdbg("crefs: %d\n", upper->crefs); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - ret = -errno; - goto errout; - } - - /* Increment the count of references to the device. If this the first - * time that the driver has been opened for this device, then initialize - * the device. - */ - - tmp = upper->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* Check if this is the first time that the driver has been opened. */ - - if (tmp == 1) - { - FAR struct pwm_lowerhalf_s *lower = upper->dev; - - /* Yes.. perform one time hardware initialization. */ - - DEBUGASSERT(lower->ops->setup != NULL); - pwmvdbg("calling setup\n"); - - ret = lower->ops->setup(lower); - if (ret < 0) - { - goto errout_with_sem; - } - } - - /* Save the new open count on success */ - - upper->crefs = tmp; - ret = OK; - -errout_with_sem: - sem_post(&upper->exclsem); - -errout: - return ret; -} - -/************************************************************************************ - * Name: pwm_close - * - * Description: - * This function is called when the PWM device is closed. - * - ************************************************************************************/ - -static int pwm_close(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct pwm_upperhalf_s *upper = inode->i_private; - int ret; - - pwmvdbg("crefs: %d\n", upper->crefs); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - ret = -errno; - goto errout; - } - - /* Decrement the references to the driver. If the reference count will - * decrement to 0, then uninitialize the driver. - */ - - if (upper->crefs > 1) - { - upper->crefs--; - } - else - { - FAR struct pwm_lowerhalf_s *lower = upper->dev; - - /* There are no more references to the port */ - - upper->crefs = 0; - - /* Disable the PWM device */ - - DEBUGASSERT(lower->ops->shutdown != NULL); - pwmvdbg("calling shutdown: %d\n"); - - lower->ops->shutdown(lower); - } - ret = OK; - -//errout_with_sem: - sem_post(&upper->exclsem); - -errout: - return ret; -} - -/************************************************************************************ - * Name: pwm_read - * - * Description: - * A dummy read method. This is provided only to satsify the VFS layer. - * - ************************************************************************************/ - -static ssize_t pwm_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - /* Return zero -- usually meaning end-of-file */ - - return 0; -} - -/************************************************************************************ - * Name: pwm_write - * - * Description: - * A dummy write method. This is provided only to satsify the VFS layer. - * - ************************************************************************************/ - -static ssize_t pwm_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) -{ - return 0; -} - -/************************************************************************************ - * Name: pwm_start - * - * Description: - * Handle the PWMIOC_START ioctl command - * - ************************************************************************************/ - -#ifdef CONFIG_PWM_PULSECOUNT -static int pwm_start(FAR struct pwm_upperhalf_s *upper, unsigned int oflags) -{ - FAR struct pwm_lowerhalf_s *lower = upper->dev; - irqstate_t flags; - int ret = OK; - - DEBUGASSERT(upper != NULL && lower->ops->start != NULL); - - /* Verify that the PWM is not already running */ - - if (!upper->started) - { - /* Disable interrupts to avoid race conditions */ - - flags = irqsave(); - - /* Indicate that if will be waiting for the pulse count to complete. - * Note that we will only wait if a non-zero pulse count is specified - * and if the PWM driver was opened in normal, blocking mode. Also - * assume for now that the pulse train will be successfully started. - * - * We do these things before starting the PWM to avoid race conditions. - */ - - upper->waiting = (upper->info.count > 0) && ((oflags & O_NONBLOCK) == 0); - upper->started = true; - - /* Invoke the bottom half method to start the pulse train */ - - ret = lower->ops->start(lower, &upper->info, upper); - - /* A return value of zero means that the pulse train was started - * successfully. - */ - - if (ret == OK) - { - /* Should we wait for the pulse output to complete? Loop in - * in case the wakeup form sem_wait() is a false alarm. - */ - - while (upper->waiting) - { - /* Wait until we are awakened by pwm_expired(). When - * pwm_expired is called, it will post the waitsem and - * clear the waiting flag. - */ - - int tmp = sem_wait(&upper->waitsem); - DEBUGASSERT(tmp == OK || errno == EINTR); - } - } - else - { - /* Looks like we won't be waiting after all */ - - pwmvdbg("start failed: %d\n", ret); - upper->started = false; - upper->waiting = false; - } - - irqrestore(flags); - } - - return ret; -} -#else -static int pwm_start(FAR struct pwm_upperhalf_s *upper, unsigned int oflags) -{ - FAR struct pwm_lowerhalf_s *lower = upper->dev; - int ret = OK; - - DEBUGASSERT(upper != NULL && lower->ops->start != NULL); - - /* Verify that the PWM is not already running */ - - if (!upper->started) - { - /* Invoke the bottom half method to start the pulse train */ - - ret = lower->ops->start(lower, &upper->info); - - /* A return value of zero means that the pulse train was started - * successfully. - */ - - if (ret == OK) - { - /* Indicate that the pulse train has started */ - - upper->started = true; - } - } - - return ret; -} -#endif - -/************************************************************************************ - * Name: pwm_ioctl - * - * Description: - * The standard ioctl method. This is where ALL of the PWM work is done. - * - ************************************************************************************/ - -static int pwm_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct pwm_upperhalf_s *upper = inode->i_private; - FAR struct pwm_lowerhalf_s *lower = upper->dev; - int ret; - - pwmvdbg("cmd: %d arg: %ld\n", cmd, arg); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - return ret; - } - - /* Handle built-in ioctl commands */ - - switch (cmd) - { - /* PWMIOC_SETCHARACTERISTICS - Set the characteristics of the next pulsed - * output. This command will neither start nor stop the pulsed output. - * It will either setup the configuration that will be used when the - * output is started; or it will change the characteristics of the pulsed - * output on the fly if the timer is already started. - * - * ioctl argument: A read-only reference to struct pwm_info_s that provides - * the characteristics of the pulsed output. - */ - - case PWMIOC_SETCHARACTERISTICS: - { - FAR const struct pwm_info_s *info = (FAR const struct pwm_info_s*)((uintptr_t)arg); - DEBUGASSERT(info != NULL && lower->ops->start != NULL); - -#ifdef CONFIG_PWM_PULSECOUNT - pwmvdbg("PWMIOC_SETCHARACTERISTICS frequency: %d duty: %08x count: %d started: %d\n", - info->frequency, info->duty, info->count, upper->started); -#else - pwmvdbg("PWMIOC_SETCHARACTERISTICS frequency: %d duty: %08x started: %d\n", - info->frequency, info->duty, upper->started); -#endif - - /* Save the pulse train characteristics */ - - memcpy(&upper->info, info, sizeof(struct pwm_info_s)); - - /* If PWM is already running, then re-start it with the new characteristics */ - - if (upper->started) - { -#ifdef CONFIG_PWM_PULSECOUNT - ret = lower->ops->start(lower, &upper->info, upper); -#else - ret = lower->ops->start(lower, &upper->info); -#endif - } - } - break; - - /* PWMIOC_GETCHARACTERISTICS - Get the currently selected characteristics of - * the pulsed output (independent of whether the output is start or stopped). - * - * ioctl argument: A reference to struct pwm_info_s to recevie the - * characteristics of the pulsed output. - */ - - case PWMIOC_GETCHARACTERISTICS: - { - FAR struct pwm_info_s *info = (FAR struct pwm_info_s*)((uintptr_t)arg); - DEBUGASSERT(info != NULL); - - memcpy(info, &upper->info, sizeof(struct pwm_info_s)); - -#ifdef CONFIG_PWM_PULSECOUNT - pwmvdbg("PWMIOC_GETCHARACTERISTICS frequency: %d duty: %08x count: %d\n", - info->frequency, info->duty, info->count); -#else - pwmvdbg("PWMIOC_GETCHARACTERISTICS frequency: %d duty: %08x\n", - info->frequency, info->duty); -#endif - } - break; - - /* PWMIOC_START - Start the pulsed output. The PWMIOC_SETCHARACTERISTICS - * command must have previously been sent. - * - * ioctl argument: None - */ - - case PWMIOC_START: - { -#ifdef CONFIG_PWM_PULSECOUNT - pwmvdbg("PWMIOC_START frequency: %d duty: %08x count: %d started: %d\n", - upper->info.frequency, upper->info.duty, upper->info.count, - upper->started); -#else - pwmvdbg("PWMIOC_START frequency: %d duty: %08x started: %d\n", - upper->info.frequency, upper->info.duty, upper->started); -#endif - DEBUGASSERT(lower->ops->start != NULL); - - /* Start the pulse train */ - - ret = pwm_start(upper, filep->f_oflags); - } - break; - - /* PWMIOC_STOP - Stop the pulsed output. - * - * ioctl argument: None - */ - - case PWMIOC_STOP: - { - pwmvdbg("PWMIOC_STOP: started: %d\n", upper->started); - DEBUGASSERT(lower->ops->stop != NULL); - - if (upper->started) - { - ret = lower->ops->stop(lower); - upper->started = false; -#ifdef CONFIG_PWM_PULSECOUNT - if (upper->waiting) - { - upper->waiting = FALSE; - } -#endif - } - } - break; - - /* Any unrecognized IOCTL commands might be platform-specific ioctl commands */ - - default: - { - pwmvdbg("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(lower->ops->ioctl != NULL); - ret = lower->ops->ioctl(lower, cmd, arg); - } - break; - } - - sem_post(&upper->exclsem); - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pwm_register - * - * Description: - * This function binds an instance of a "lower half" timer driver with the - * "upper half" PWM device and registers that device so that can be used - * by application code. - * - * When this function is called, the "lower half" driver should be in the - * reset state (as if the shutdown() method had already been called). - * - * Input parameters: - * path - The full path to the driver to be registers in the NuttX pseudo- - * filesystem. The recommended convention is to name all PWM drivers - * as "/dev/pwm0", "/dev/pwm1", etc. where the driver path differs only - * in the "minor" number at the end of the device name. - * dev - A pointer to an instance of lower half timer driver. This instance - * is bound to the PWM driver and must persists as long as the driver - * persists. - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -int pwm_register(FAR const char *path, FAR struct pwm_lowerhalf_s *dev) -{ - FAR struct pwm_upperhalf_s *upper; - - /* Allocate the upper-half data structure */ - - upper = (FAR struct pwm_upperhalf_s *)zalloc(sizeof(struct pwm_upperhalf_s)); - if (!upper) - { - pwmdbg("Allocation failed\n"); - return -ENOMEM; - } - - /* Initialize the PWM device structure (it was already zeroed by zalloc()) */ - - sem_init(&upper->exclsem, 0, 1); -#ifdef CONFIG_PWM_PULSECOUNT - sem_init(&upper->waitsem, 0, 0); -#endif - upper->dev = dev; - - /* Register the PWM device */ - - pwmvdbg("Registering %s\n", path); - return register_driver(path, &g_pwmops, 0666, upper); -} - -/**************************************************************************** - * Name: pwm_expired - * - * Description: - * If CONFIG_PWM_PULSECOUNT is defined and the pulse count was configured - * to a non-zero value, then the "upper half" driver will wait for the - * pulse count to expire. The sequence of expected events is as follows: - * - * 1. The upper half driver calls the start method, providing the lower - * half driver with the pulse train characteristics. If a fixed - * number of pulses is required, the 'count' value will be nonzero. - * 2. The lower half driver's start() methoc must verify that it can - * support the request pulse train (frequency, duty, AND pulse count). - * It it cannot, it should return an error. If the pulse count is - * non-zero, it should set up the hardware for that number of pulses - * and return success. NOTE: That is CONFIG_PWM_PULSECOUNT is - * defined, the start() method receives an additional parameter - * that must be used in this callback. - * 3. When the start() method returns success, the upper half driver - * will "sleep" until the pwm_expired method is called. - * 4. When the lower half detects that the pulse count has expired - * (probably through an interrupt), it must call the pwm_expired - * interface using the handle that was previously passed to the - * start() method - * - * Input parameters: - * handle - This is the handle that was provided to the lower-half - * start() method. - * - * Returned Value: - * None - * - * Assumptions: - * This function may be called from an interrupt handler. - * - ****************************************************************************/ - -#ifdef CONFIG_PWM_PULSECOUNT -void pwm_expired(FAR void *handle) -{ - FAR struct pwm_upperhalf_s *upper = (FAR struct pwm_upperhalf_s *)handle; - - pwmllvdbg("started: %d waiting: %d\n", upper->started, upper->waiting); - - /* Make sure that the PWM is started */ - - if (upper->started) - { - /* Is there a thread waiting for the pulse train to complete? */ - - if (upper->waiting) - { - /* Yes.. clear the waiting flag and awakened the waiting thread */ - - upper->waiting = false; - sem_post(&upper->waitsem); - } - - /* The PWM is now stopped */ - - upper->started = false; - } -} -#endif - -#endif /* CONFIG_PWM */ diff --git a/nuttx/drivers/ramdisk.c b/nuttx/drivers/ramdisk.c deleted file mode 100644 index 91912b25c..000000000 --- a/nuttx/drivers/ramdisk.c +++ /dev/null @@ -1,342 +0,0 @@ -/**************************************************************************** - * drivers/ramdisk.c - * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/**************************************************************************** - * Private Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct rd_struct_s -{ - uint32_t rd_nsectors; /* Number of sectors on device */ - uint16_t rd_sectsize; /* The size of one sector */ -#ifdef CONFIG_FS_WRITABLE - bool rd_writeenabled; /* true: can write to ram disk */ - uint8_t *rd_buffer; /* RAM disk backup memory */ -#else - const uint8_t *rd_buffer; /* ROM disk backup memory */ -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int rd_open(FAR struct inode *inode); -static int rd_close(FAR struct inode *inode); -static ssize_t rd_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors); -#ifdef CONFIG_FS_WRITABLE -static ssize_t rd_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, unsigned int nsectors); -#endif -static int rd_geometry(FAR struct inode *inode, struct geometry *geometry); -static int rd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct block_operations g_bops = -{ - rd_open, /* open */ - rd_close, /* close */ - rd_read, /* read */ -#ifdef CONFIG_FS_WRITABLE - rd_write, /* write */ -#else - NULL, /* write */ -#endif - rd_geometry, /* geometry */ - rd_ioctl /* ioctl */ -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: rd_open - * - * Description: Open the block device - * - ****************************************************************************/ - -static int rd_open(FAR struct inode *inode) -{ - fvdbg("Entry\n"); - return OK; -} - -/**************************************************************************** - * Name: rd_closel - * - * Description: close the block device - * - ****************************************************************************/ - -static int rd_close(FAR struct inode *inode) -{ - fvdbg("Entry\n"); - return OK; -} - -/**************************************************************************** - * Name: rd_read - * - * Description: Read the specified numer of sectors - * - ****************************************************************************/ - -static ssize_t rd_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - struct rd_struct_s *dev; - - DEBUGASSERT(inode && inode->i_private); - dev = (struct rd_struct_s *)inode->i_private; - - fvdbg("sector: %d nsectors: %d sectorsize: %d\n", - start_sector, dev->rd_sectsize, nsectors); - - if (start_sector < dev->rd_nsectors && - start_sector + nsectors <= dev->rd_nsectors) - { - fvdbg("Transfer %d bytes from %p\n", - nsectors * dev->rd_sectsize, - &dev->rd_buffer[start_sector * dev->rd_sectsize]); - - memcpy(buffer, - &dev->rd_buffer[start_sector * dev->rd_sectsize], - nsectors * dev->rd_sectsize); - return nsectors; - } - - return -EINVAL; -} - -/**************************************************************************** - * Name: rd_write - * - * Description: Write the specified number of sectors - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static ssize_t rd_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, unsigned int nsectors) -{ - struct rd_struct_s *dev; - - DEBUGASSERT(inode && inode->i_private); - dev = (struct rd_struct_s *)inode->i_private; - - fvdbg("sector: %d nsectors: %d sectorsize: %d\n", - start_sector, dev->rd_sectsize, nsectors); - - if (!dev->rd_writeenabled) - { - return -EACCES; - } - else if (start_sector < dev->rd_nsectors && - start_sector + nsectors <= dev->rd_nsectors) - { - fvdbg("Transfer %d bytes from %p\n", - nsectors * dev->rd_sectsize, - &dev->rd_buffer[start_sector * dev->rd_sectsize]); - - memcpy(&dev->rd_buffer[start_sector * dev->rd_sectsize], - buffer, - nsectors * dev->rd_sectsize); - return nsectors; - } - - return -EFBIG; -} -#endif - -/**************************************************************************** - * Name: rd_geometry - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int rd_geometry(FAR struct inode *inode, struct geometry *geometry) -{ - struct rd_struct_s *dev; - - fvdbg("Entry\n"); - - DEBUGASSERT(inode); - if (geometry) - { - dev = (struct rd_struct_s *)inode->i_private; - geometry->geo_available = true; - geometry->geo_mediachanged = false; -#ifdef CONFIG_FS_WRITABLE - geometry->geo_writeenabled = dev->rd_writeenabled; -#else - geometry->geo_writeenabled = false; -#endif - geometry->geo_nsectors = dev->rd_nsectors; - geometry->geo_sectorsize = dev->rd_sectsize; - - fvdbg("available: true mediachanged: false writeenabled: %s\n", - geometry->geo_writeenabled ? "true" : "false"); - fvdbg("nsectors: %d sectorsize: %d\n", - geometry->geo_nsectors, geometry->geo_sectorsize); - - return OK; - } - - return -EINVAL; -} - -/**************************************************************************** - * Name: rd_ioctl - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int rd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) -{ - struct rd_struct_s *dev ; - void **ppv = (void**)((uintptr_t)arg); - - fvdbg("Entry\n"); - - /* Only one ioctl command is supported */ - - DEBUGASSERT(inode && inode->i_private); - if (cmd == BIOC_XIPBASE && ppv) - { - dev = (struct rd_struct_s *)inode->i_private; - *ppv = (void*)dev->rd_buffer; - - fvdbg("ppv: %p\n", *ppv); - return OK; - } - - return -ENOTTY; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ramdisk_register - * - * Description: Register the a ramdisk - - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -int ramdisk_register(int minor, uint8_t *buffer, uint32_t nsectors, - uint16_t sectsize, bool writeenabled) -#else -int romdisk_register(int minor, uint8_t *buffer, uint32_t nsectors, - uint16_t sectsize) -#endif -{ - struct rd_struct_s *dev; - char devname[16]; - int ret = -ENOMEM; - - fvdbg("buffer: %p nsectors: %d sectsize: %d\n", buffer, nsectors, sectsize); - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (minor < 0 || minor > 255 || !buffer || !nsectors || !sectsize) - { - return -EINVAL; - } -#endif - - /* Allocate a ramdisk device structure */ - - dev = (struct rd_struct_s *)kmalloc(sizeof(struct rd_struct_s)); - if (dev) - { - /* Initialize the ramdisk device structure */ - - dev->rd_nsectors = nsectors; /* Number of sectors on device */ - dev->rd_sectsize = sectsize; /* The size of one sector */ -#ifdef CONFIG_FS_WRITABLE - dev->rd_writeenabled = writeenabled; /* true: can write to ram disk */ -#endif - dev->rd_buffer = buffer; /* RAM disk backup memory */ - - /* Create a ramdisk device name */ - - snprintf(devname, 16, "/dev/ram%d", minor); - - /* Inode private data is a reference to the ramdisk device stgructure */ - - ret = register_blockdriver(devname, &g_bops, 0, dev); - if (ret < 0) - { - fdbg("register_blockdriver failed: %d\n", -ret); - kfree(dev); - } - } - return ret; -} diff --git a/nuttx/drivers/rwbuffer.c b/nuttx/drivers/rwbuffer.c deleted file mode 100644 index 076ebc781..000000000 --- a/nuttx/drivers/rwbuffer.c +++ /dev/null @@ -1,682 +0,0 @@ -/**************************************************************************** - * drivers/rwbuffer.c - * - * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) - -/**************************************************************************** - * Preprocessor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -#ifndef CONFIG_SCHED_WORKQUEUE -# error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" -#endif - -#ifndef CONFIG_FS_WRDELAY -# define CONFIG_FS_WRDELAY 350 -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/**************************************************************************** - * Public Variables - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: rwb_semtake - ****************************************************************************/ - -static void rwb_semtake(sem_t *sem) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(sem) != 0) - { - /* The only case that an error should occr here is if - * the wait was awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -/**************************************************************************** - * Name: rwb_semgive - ****************************************************************************/ - -#define rwb_semgive(s) sem_post(s) - -/**************************************************************************** - * Name: rwb_overlap - ****************************************************************************/ - -static inline bool rwb_overlap(off_t blockstart1, size_t nblocks1, - off_t blockstart2, size_t nblocks2) -{ - off_t blockend1 = blockstart1 + nblocks1; - off_t blockend2 = blockstart2 + nblocks2; - - /* If the buffer 1 is wholly outside of buffer 2, return false */ - - if ((blockend1 < blockstart2) || /* Wholly "below" */ - (blockstart1 > blockend2)) /* Wholly "above" */ - { - return false; - } - else - { - return true; - } -} - -/**************************************************************************** - * Name: rwb_resetwrbuffer - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITEBUFFER -static inline void rwb_resetwrbuffer(struct rwbuffer_s *rwb) -{ - /* We assume that the caller holds the wrsem */ - - rwb->wrnblocks = 0; - rwb->wrblockstart = (off_t)-1; - rwb->wrexpectedblock = (off_t)-1; -} -#endif - -/**************************************************************************** - * Name: rwb_wrflush - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITEBUFFER -static void rwb_wrflush(struct rwbuffer_s *rwb) -{ - int ret; - - fvdbg("Timeout!\n"); - - rwb_semtake(&rwb->wrsem); - if (rwb->wrnblocks) - { - fvdbg("Flushing: blockstart=0x%08lx nblocks=%d from buffer=%p\n", - (long)rwb->wrblockstart, rwb->wrnblocks, rwb->wrbuffer); - - /* Flush cache. On success, the flush method will return the number - * of blocks written. Anything other than the number requested is - * an error. - */ - - ret = rwb->wrflush(rwb->dev, rwb->wrbuffer, rwb->wrblockstart, rwb->wrnblocks); - if (ret != rwb->wrnblocks) - { - fdbg("ERROR: Error flushing write buffer: %d\n", ret); - } - - rwb_resetwrbuffer(rwb); - } - - rwb_semgive(&rwb->wrsem); -} -#endif - -/**************************************************************************** - * Name: rwb_wrtimeout - ****************************************************************************/ - -static void rwb_wrtimeout(FAR void *arg) -{ - /* The following assumes that the size of a pointer is 4-bytes or less */ - - FAR struct rwbuffer_s *rwb = (struct rwbuffer_s *)arg; - DEBUGASSERT(rwb != NULL); - - /* If a timeout elpases with with write buffer activity, this watchdog - * handler function will be evoked on the thread of execution of the - * worker thread. - */ - - rwb_wrflush(rwb); -} - -/**************************************************************************** - * Name: rwb_wrstarttimeout - ****************************************************************************/ - -static void rwb_wrstarttimeout(FAR struct rwbuffer_s *rwb) -{ - /* CONFIG_FS_WRDELAY provides the delay period in milliseconds. CLK_TCK - * provides the clock tick of the system (frequency in Hz). - */ - - int ticks = (CONFIG_FS_WRDELAY + CLK_TCK/2) / CLK_TCK; - (void)work_queue(LPWORK, &rwb->work, rwb_wrtimeout, (FAR void *)rwb, ticks); -} - -/**************************************************************************** - * Name: rwb_wrcanceltimeout - ****************************************************************************/ - -static inline void rwb_wrcanceltimeout(struct rwbuffer_s *rwb) -{ - (void)work_cancel(LPWORK, &rwb->work); -} - -/**************************************************************************** - * Name: rwb_writebuffer - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITEBUFFER -static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb, - off_t startblock, uint32_t nblocks, - FAR const uint8_t *wrbuffer) -{ - int ret; - - /* Write writebuffer Logic */ - - rwb_wrcanceltimeout(rwb); - - /* First: Should we flush out our cache? We would do that if (1) we already - * buffering blocks and the next block writing is not in the same sequence, - * or (2) the number of blocks would exceed our allocated buffer capacity - */ - - if (((startblock != rwb->wrexpectedblock) && (rwb->wrnblocks)) || - ((rwb->wrnblocks + nblocks) > rwb->wrmaxblocks)) - { - fvdbg("writebuffer miss, expected: %08x, given: %08x\n", - rwb->wrexpectedblock, startblock); - - /* Flush the write buffer */ - - ret = rwb->wrflush(rwb, rwb->wrbuffer, rwb->wrblockstart, rwb->wrnblocks); - if (ret < 0) - { - fdbg("ERROR: Error writing multiple from cache: %d\n", -ret); - return ret; - } - - rwb_resetwrbuffer(rwb); - } - - /* writebuffer is empty? Then initialize it */ - - if (!rwb->wrnblocks) - { - fvdbg("Fresh cache starting at block: 0x%08x\n", startblock); - rwb->wrblockstart = startblock; - } - - /* Add data to cache */ - - fvdbg("writebuffer: copying %d bytes from %p to %p\n", - nblocks * wrb->blocksize, wrbuffer, - &rwb->wrbuffer[rwb->wrnblocks * rwb->blocksize]); - memcpy(&rwb->wrbuffer[rwb->wrnblocks * rwb->blocksize], - wrbuffer, nblocks * rwb->blocksize); - - rwb->wrnblocks += nblocks; - rwb->wrexpectedblock = rwb->wrblockstart + rwb->wrnblocks; - rwb_wrstarttimeout(rwb); - return nblocks; -} -#endif - -/**************************************************************************** - * Name: rwb_resetrhbuffer - ****************************************************************************/ - -#ifdef CONFIG_FS_READAHEAD -static inline void rwb_resetrhbuffer(struct rwbuffer_s *rwb) -{ - /* We assume that the caller holds the readAheadBufferSemphore */ - - rwb->rhnblocks = 0; - rwb->rhblockstart = (off_t)-1; -} -#endif - -/**************************************************************************** - * Name: rwb_bufferread - ****************************************************************************/ - -#ifdef CONFIG_FS_READAHEAD -static inline void -rwb_bufferread(struct rwbuffer_s *rwb, off_t startblock, - size_t nblocks, uint8_t **rdbuffer) -{ - /* We assume that (1) the caller holds the readAheadBufferSemphore, and (2) - * that the caller already knows that all of the blocks are in the - * read-ahead buffer. - */ - - /* Convert the units from blocks to bytes */ - - off_t blockoffset = startblock - rwb->rhblockstart; - off_t byteoffset = rwb->blocksize * blockoffset; - size_t nbytes = rwb->blocksize * nblocks; - - /* Get the byte address in the read-ahead buffer */ - - uint8_t *rhbuffer = rwb->rhbuffer + byteoffset; - - /* Copy the data from the read-ahead buffer into the IO buffer */ - - memcpy(*rdbuffer, rhbuffer, nbytes); - - /* Update the caller's copy for the next address */ - - *rdbuffer += nbytes; -} -#endif - -/**************************************************************************** - * Name: rwb_rhreload - ****************************************************************************/ - -#ifdef CONFIG_FS_READAHEAD -static int rwb_rhreload(struct rwbuffer_s *rwb, off_t startblock) -{ - /* Get the block number +1 of the last block that will fit in the - * read-ahead buffer - */ - - off_t endblock = startblock + rwb->rhmaxblocks; - size_t nblocks; - int ret; - - /* Reset the read buffer */ - - rwb_resetrhbuffer(rwb); - - /* Make sure that we don't read past the end of the device */ - - if (endblock > rwb->nblocks) - { - endblock = rwb->nblocks; - } - - nblocks = endblock - startblock; - - /* Now perform the read */ - - ret = rwb->rhreload(rwb->dev, rwb->rhbuffer, startblock, nblocks); - if (ret == nblocks) - { - /* Update information about what is in the read-ahead buffer */ - - rwb->rhnblocks = nblocks; - rwb->rhblockstart = startblock; - - /* The return value is not the number of blocks we asked to be loaded. */ - - return nblocks; - } - - return -EIO; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ -/**************************************************************************** - * Name: rwb_initialize - ****************************************************************************/ - -int rwb_initialize(FAR struct rwbuffer_s *rwb) -{ - uint32_t allocsize; - - /* Sanity checking */ - - DEBUGASSERT(rwb != NULL); - DEBUGASSERT(rwb->blocksize > 0); - DEBUGASSERT(rwb->nblocks > 0); - DEBUGASSERT(rwb->dev != NULL); - - /* Setup so that rwb_uninitialize can handle a failure */ - -#ifdef CONFIG_FS_WRITEBUFFER - DEBUGASSERT(rwb->wrflush!= NULL); - rwb->wrbuffer = NULL; -#endif -#ifdef CONFIG_FS_READAHEAD - DEBUGASSERT(rwb->rhreload != NULL); - rwb->rhbuffer = NULL; -#endif - -#ifdef CONFIG_FS_WRITEBUFFER - fvdbg("Initialize the write buffer\n"); - - /* Initialize the write buffer access semaphore */ - - sem_init(&rwb->wrsem, 0, 1); - - /* Initialize write buffer parameters */ - - rwb_resetwrbuffer(rwb); - - /* Allocate the write buffer */ - - rwb->wrbuffer = NULL; - if (rwb->wrmaxblocks > 0) - { - allocsize = rwb->wrmaxblocks * rwb->blocksize; - rwb->wrbuffer = kmalloc(allocsize); - if (!rwb->wrbuffer) - { - fdbg("Write buffer kmalloc(%d) failed\n", allocsizee); - return -ENOMEM; - } - } - - fvdbg("Write buffer size: %d bytes\n", allocsize); -#endif /* CONFIG_FS_WRITEBUFFER */ - -#ifdef CONFIG_FS_READAHEAD - fvdbg("Initialize the read-ahead buffer\n"); - - /* Initialize the read-ahead buffer access semaphore */ - - sem_init(&rwb->rhsem, 0, 1); - - /* Initialize read-ahead buffer parameters */ - - rwb_resetrhbuffer(rwb); - - /* Allocate the read-ahead buffer */ - - rwb->rhbuffer = NULL; - if (rwb->rhmaxblocks > 0) - { - allocsize = rwb->rhmaxblocks * rwb->blocksize; - rwb->rhbuffer = kmalloc(allocsize); - if (!rwb->rhbuffer) - { - fdbg("Read-ahead buffer kmalloc(%d) failed\n", allocsize); - return -ENOMEM; - } - } - - fvdbg("Read-ahead buffer size: %d bytes\n", allocsize); -#endif /* CONFIG_FS_READAHEAD */ - return 0; -} - -/**************************************************************************** - * Name: rwb_uninitialize - ****************************************************************************/ - -void rwb_uninitialize(FAR struct rwbuffer_s *rwb) -{ -#ifdef CONFIG_FS_WRITEBUFFER - rwb_wrcanceltimeout(rwb); - sem_destroy(&rwb->wrsem); - if (rwb->wrbuffer) - { - kfree(rwb->wrbuffer); - } -#endif - -#ifdef CONFIG_FS_READAHEAD - sem_destroy(&rwb->rhsem); - if (rwb->rhbuffer) - { - kfree(rwb->rhbuffer); - } -#endif -} - -/**************************************************************************** - * Name: rwb_read - ****************************************************************************/ - -int rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock, uint32_t nblocks, - FAR uint8_t *rdbuffer) -{ - uint32_t remaining; - - fvdbg("startblock=%ld nblocks=%ld rdbuffer=%p\n", - (long)startblock, (long)nblocks, rdbuffer); - -#ifdef CONFIG_FS_WRITEBUFFER - /* If the new read data overlaps any part of the write buffer, then - * flush the write data onto the physical media before reading. We - * could attempt some more exotic handling -- but this simple logic - * is well-suited for simple streaming applications. - */ - - if (rwb->wrmaxblocks > 0) - { - /* If the write buffer overlaps the block(s) requested, then flush the - * write buffer. - */ - - rwb_semtake(&rwb->wrsem); - if (rwb_overlap(rwb->wrblockstart, rwb->wrnblocks, startblock, nblocks)) - { - rwb_wrflush(rwb); - } - rwb_semgive(&rwb->wrsem); - } -#endif - -#ifdef CONFIG_FS_READAHEAD - /* Loop until we have read all of the requested blocks */ - - rwb_semtake(&rwb->rhsem); - for (remaining = nblocks; remaining > 0;) - { - /* Is there anything in the read-ahead buffer? */ - - if (rwb->rhnblocks > 0) - { - off_t startblock = startblock; - size_t nbufblocks = 0; - off_t bufferend; - - /* Loop for each block we find in the read-head buffer. Count the - * number of buffers that we can read from read-ahead buffer. - */ - - bufferend = rwb->rhblockstart + rwb->rhnblocks; - - while ((startblock >= rwb->rhblockstart) && - (startblock < bufferend) && - (remaining > 0)) - { - /* This is one more that we will read from the read ahead buffer */ - - nbufblocks++; - - /* And one less that we will read from the media */ - - startblock++; - remaining--; - } - - /* Then read the data from the read-ahead buffer */ - - rwb_bufferread(rwb, startblock, nbufblocks, &rdbuffer); - } - - /* If we did not get all of the data from the buffer, then we have to refill - * the buffer and try again. - */ - - if (remaining > 0) - { - int ret = rwb_rhreload(rwb, startblock); - if (ret < 0) - { - fdbg("ERROR: Failed to fill the read-ahead buffer: %d\n", -ret); - return ret; - } - } - } - - /* On success, return the number of blocks that we were requested to read. - * This is for compatibility with the normal return of a block driver read - * method - */ - - rwb_semgive(&rwb->rhsem); - return 0; -#else - return rwb->rhreload(rwb->dev, startblock, nblocks, rdbuffer); -#endif -} - -/**************************************************************************** - * Name: rwb_write - ****************************************************************************/ - -int rwb_write(FAR struct rwbuffer_s *rwb, off_t startblock, - size_t nblocks, FAR const uint8_t *wrbuffer) -{ - int ret; - -#ifdef CONFIG_FS_READAHEAD - /* If the new write data overlaps any part of the read buffer, then - * flush the data from the read buffer. We could attempt some more - * exotic handling -- but this simple logic is well-suited for simple - * streaming applications. - */ - - rwb_semtake(&rwb->rhsem); - if (rwb_overlap(rwb->rhblockstart, rwb->rhnblocks, startblock, nblocks)) - { - rwb_resetrhbuffer(rwb); - } - rwb_give(&rwb->rhsem); -#endif - -#ifdef CONFIG_FS_WRITEBUFFER - fvdbg("startblock=%d wrbuffer=%p\n", startblock, wrbuffer); - - /* Use the block cache unless the buffer size is bigger than block cache */ - - if (nblocks > rwb->wrmaxblocks) - { - /* First flush the cache */ - - rwb_semtake(&rwb->wrsem); - rwb_wrflush(rwb); - rwb_semgive(&rwb->wrsem); - - /* Then transfer the data directly to the media */ - - ret = rwb->wrflush(rwb->dev, startblock, nblocks, wrbuffer); - } - else - { - /* Buffer the data in the write buffer */ - - ret = rwb_writebuffer(rwb, startblock, nblocks, wrbuffer); - } - - /* On success, return the number of blocks that we were requested to write. - * This is for compatibility with the normal return of a block driver write - * method - */ - - return ret; - -#else - - return rwb->wrflush(rwb->dev, startblock, nblocks, wrbuffer); - -#endif -} - -/**************************************************************************** - * Name: rwb_mediaremoved - * - * Description: - * The following function is called when media is removed - * - ****************************************************************************/ - -int rwb_mediaremoved(FAR struct rwbuffer_s *rwb) -{ -#ifdef CONFIG_FS_WRITEBUFFER - rwb_semtake(&rwb->wrsem); - rwb_resetwrbuffer(rwb); - rwb_semgive(&rwb->wrsem); -#endif - -#ifdef CONFIG_FS_READAHEAD - rwb_semtake(&rwb->rhsem); - rwb_resetrhbuffer(rwb); - rwb_semgive(&rwb->rhsem); -#endif - return 0; -} - -#endif /* CONFIG_FS_WRITEBUFFER || CONFIG_FS_READAHEAD */ - diff --git a/nuttx/drivers/sensors/Kconfig b/nuttx/drivers/sensors/Kconfig deleted file mode 100644 index 386cdc3a8..000000000 --- a/nuttx/drivers/sensors/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# -config LIS331DL - bool "ST LIS331DL device support" - default n - select I2C - -config I2C_LM75 - bool - default y if LM75 - -config LM75 - bool "STMicro LM-75 Temperature Sensor support" - default n - select I2C - select I2C_LM75 - -config DEBUG_LM75 - bool "Enable LM-75 debug" - default n - depends on LM75 - -config QENCODER - bool "Qencoder" - default n - -config DEBUG_QENCODER - bool "Enable Qencoder Debug" - default n - depends on QENCODER - diff --git a/nuttx/drivers/sensors/Make.defs b/nuttx/drivers/sensors/Make.defs deleted file mode 100644 index 1713edb99..000000000 --- a/nuttx/drivers/sensors/Make.defs +++ /dev/null @@ -1,60 +0,0 @@ -############################################################################ -# drivers/sensors/Make.defs -# -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Include sensor drivers -# These drivers depend on I2C support - -ifeq ($(CONFIG_I2C),y) - -ifeq ($(CONFIG_I2C_TRANSFER),y) - CSRCS += lis331dl.c -endif - -ifeq ($(CONFIG_I2C_LM75),y) - CSRCS += lm75.c -endif -endif - -# Quadrature encoder upper half - -ifeq ($(CONFIG_QENCODER),y) - CSRCS += qencoder.c -endif - -# Include sensor driver build support - -DEPPATH += --dep-path sensors -VPATH += :sensors -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)sensors} diff --git a/nuttx/drivers/sensors/lis331dl.c b/nuttx/drivers/sensors/lis331dl.c deleted file mode 100644 index 2117a7ebd..000000000 --- a/nuttx/drivers/sensors/lis331dl.c +++ /dev/null @@ -1,320 +0,0 @@ -/**************************************************************************** - * drivers/sensors/lis331dl.c - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * - * Authors: Uros Platise - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/** \file - * \author Uros Platise - * \brief ST LIS331DL I2C Device Driver - **/ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/************************************************************************************ - * LIS331DL Internal Registers - ************************************************************************************/ - -#define ST_LIS331DL_WHOAMI 0x0F /* who am I register */ -#define ST_LIS331DL_WHOAMI_VALUE 0x3B /* Valid result is 0x3B */ - -#define ST_LIS331DL_CTRL_REG1 0x20 -#define ST_LIS331DL_CR1_DR 0x80 /* Data-rate selection 0: 100 Hz, 1: 400 Hz */ -#define ST_LIS331DL_CR1_PD 0x40 /* Active Mode (1) / Power-down (0) */ -#define ST_LIS331DL_CR1_FS 0x20 /* Full Scale (1) +-9g or Normal Scale (0) +-2g */ -#define ST_LIS331DL_CR1_ST 0x18 /* Self test enable */ -#define ST_LIS331DL_CR1_ZEN 0x04 /* Z-Axis Enable */ -#define ST_LIS331DL_CR1_YEN 0x02 /* Y-Axis Enable */ -#define ST_LIS331DL_CR1_XEN 0x01 /* X-Axis Enable */ - -#define ST_LIS331DL_CTRL_REG2 0x21 -#define ST_LIS331DL_CTRL_REG3 0x22 - -#define ST_LIS331DL_HP_FILTER_RESET 0x23 - -#define ST_LIS331DL_STATUS_REG 0x27 /* Status Register */ -#define ST_LIS331DL_SR_ZYXOR 0x80 /* OR'ed X,Y and Z data over-run */ -#define ST_LIS331DL_SR_ZOR 0x40 /* individual data over-run ... */ -#define ST_LIS331DL_SR_YOR 0x20 -#define ST_LIS331DL_SR_XOR 0x10 -#define ST_LIS331DL_SR_ZYXDA 0x08 /* OR'ed X,Y and Z data available */ -#define ST_LIS331DL_SR_ZDA 0x04 /* individual data available ... */ -#define ST_LIS331DL_SR_YDA 0x02 -#define ST_LIS331DL_SR_XDA 0x01 - -#define ST_LIS331DL_OUT_X 0x29 -#define ST_LIS331DL_OUT_Y 0x2B -#define ST_LIS331DL_OUT_Z 0x2D - - -/************************************************************************************ - * Private Data Types - ************************************************************************************/ - -struct lis331dl_dev_s { - struct i2c_dev_s * i2c; - - uint8_t address; - struct lis331dl_vector_s a; - uint8_t cr1; - uint8_t cr2; - uint8_t cr3; -}; - - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/** LIS331DL Access with range check - * - * \param dev LIS331 DL Private Structure - * \param subaddr LIS331 Sub Address - * \param buf Pointer to buffer, either for read or write access - * \param length when >0 it denotes read access, when <0 it denotes write access of -length - * \return OK on success or errno is set. - **/ -int lis331dl_access(struct lis331dl_dev_s * dev, uint8_t subaddr, uint8_t *buf, int length) -{ - uint16_t flags = 0; - int retval; - - if (length > 0) { - flags = I2C_M_READ; - } - else { - flags = I2C_M_NORESTART; - length = -length; - } - - /* Check valid address ranges and set auto address increment flag */ - - if (subaddr == 0x0F) { - if (length > 1) length = 1; - } - else if (subaddr >= 0x20 && subaddr < 0x24) { - if (length > (0x24 - subaddr) ) length = 0x24 - subaddr; - } - else if (subaddr >= 0x27 && subaddr < 0x2E) { - if (length > (0x2E - subaddr) ) length = 0x2E - subaddr; - } - else if (subaddr >= 0x30 && subaddr < 0x40) { - if (length > (0x40 - subaddr) ) length = 0x40 - subaddr; - } - else { - errno = EFAULT; - return ERROR; - } - - if (length > 1) subaddr |= 0x80; - - /* Create message and send */ - - struct i2c_msg_s msgv[2] = { - { - .addr = dev->address, - .flags = 0, - .buffer = &subaddr, - .length = 1 - }, - { - .addr = dev->address, - .flags = flags, - .buffer = buf, - .length = length - } - }; - - if ( (retval = I2C_TRANSFER(dev->i2c, msgv, 2)) == OK ) - return length; - - return retval; -} - - -int lis331dl_readregs(struct lis331dl_dev_s * dev) -{ - if (lis331dl_access(dev, ST_LIS331DL_CTRL_REG1, &dev->cr1, 3) != 3) return ERROR; - return OK; -} - - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -struct lis331dl_dev_s * lis331dl_init(struct i2c_dev_s * i2c, uint16_t address) -{ - struct lis331dl_dev_s * dev; - uint8_t retval; - - ASSERT(i2c); - ASSERT(address); - - if ( (dev = kmalloc( sizeof(struct lis331dl_dev_s) )) == NULL ) { - errno = ENOMEM; - return NULL; - } - - memset(dev, 0, sizeof(struct lis331dl_dev_s)); - dev->i2c = i2c; - dev->address = address; - - /* Probe device */ - - if (lis331dl_access(dev, ST_LIS331DL_WHOAMI, &retval, 1) > 0) { - - /* Check chip identification, in the future several more compatible parts - * may be added here. - */ - - if (retval == ST_LIS331DL_WHOAMI_VALUE) { - - /* Copy LIS331DL registers to our private structure and power-up device */ - - if (lis331dl_readregs(dev)==OK && lis331dl_powerup(dev)==OK) { - - /* Normal exit point */ - errno = 0; - return dev; - } - retval = errno; - } - - /* Otherwise, we mark an invalid device found at given address */ - retval = ENODEV; - } - else { - /* No response at given address is marked as */ - retval = EFAULT; - } - - /* Error exit */ - kfree(dev); - errno = retval; - return NULL; -} - - -int lis331dl_deinit(struct lis331dl_dev_s * dev) -{ - ASSERT(dev); - - lis331dl_powerdown(dev); - kfree(dev); - - return OK; -} - - -int lis331dl_powerup(struct lis331dl_dev_s * dev) -{ - dev->cr1 = ST_LIS331DL_CR1_PD | - ST_LIS331DL_CR1_ZEN | ST_LIS331DL_CR1_YEN | ST_LIS331DL_CR1_XEN; - dev->cr2 = 0; - dev->cr3 = 0; - - if (lis331dl_access(dev, ST_LIS331DL_CTRL_REG1, &dev->cr1, -3) == 3) return OK; - return ERROR; -} - - -int lis331dl_powerdown(struct lis331dl_dev_s * dev) -{ - dev->cr1 = ST_LIS331DL_CR1_ZEN | ST_LIS331DL_CR1_YEN | ST_LIS331DL_CR1_XEN; - dev->cr2 = 0; - dev->cr3 = 0; - - if (lis331dl_access(dev, ST_LIS331DL_CTRL_REG1, &dev->cr1, -3) == 3) return OK; - return ERROR; -} - - -int lis331dl_setconversion(struct lis331dl_dev_s * dev, bool full, bool fast) -{ - dev->cr1 = ST_LIS331DL_CR1_PD | - (full ? ST_LIS331DL_CR1_FS : 0) | (fast ? ST_LIS331DL_CR1_DR : 0) | - ST_LIS331DL_CR1_ZEN | ST_LIS331DL_CR1_YEN | ST_LIS331DL_CR1_XEN; - - if (lis331dl_access(dev, ST_LIS331DL_CTRL_REG1, &dev->cr1, -1) == 1) return OK; - return ERROR; -} - - -int lis331dl_getprecision(struct lis331dl_dev_s * dev) -{ - if (dev->cr1 & ST_LIS331DL_CR1_FS) - return 9200/127; /* typ. 9.2g full scale */ - return 2300/127; /* typ. 2.3g full scale */ -} - - -int lis331dl_getsamplerate(struct lis331dl_dev_s * dev) -{ - if (dev->cr1 & ST_LIS331DL_CR1_DR) - return 400; - return 100; -} - - -const struct lis331dl_vector_s * lis331dl_getreadings(struct lis331dl_dev_s * dev) -{ - uint8_t retval[7]; - - ASSERT(dev); - - if (lis331dl_access(dev, ST_LIS331DL_STATUS_REG, retval, 7) == 7) { - - /* If result is not yet ready, return NULL */ - - if ( !(retval[0] & ST_LIS331DL_SR_ZYXDA) ) { - errno = EAGAIN; - return NULL; - } - - dev->a.x = retval[2]; - dev->a.y = retval[4]; - dev->a.z = retval[6]; - return &dev->a; - } - - return NULL; -} diff --git a/nuttx/drivers/sensors/lm75.c b/nuttx/drivers/sensors/lm75.c deleted file mode 100644 index 2d3346447..000000000 --- a/nuttx/drivers/sensors/lm75.c +++ /dev/null @@ -1,537 +0,0 @@ -/**************************************************************************** - * drivers/sensors/lm75.c - * Character driver for the STMicro LM-75 Temperature Sensor - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_I2C) && defined(CONFIG_I2C_LM75) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Centigrade to Fahrenheit conversion: F = 9*C/5 + 32 */ - -#define B16_9DIV5 (9 * 65536 / 5) -#define B16_32 (32 * 65536) - -/* Debug for this file only */ - -#ifdef CONFIG_DEBUG_LM75 -# define lm75dbg dbg -#else -# ifdef CONFIG_CPP_HAVE_VARARGS -# define lm75dbg(x...) -# else -# define lm75dbg (void) -# endif -#endif - -/**************************************************************************** - * Private - ****************************************************************************/ - -struct lm75_dev_s -{ - FAR struct i2c_dev_s *i2c; /* I2C interface */ - uint8_t addr; /* I2C address */ - bool fahrenheit; /* true: temperature will be reported in fahrenheit */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* I2C Helpers */ - -static int lm75_readb16(FAR struct lm75_dev_s *priv, uint8_t regaddr, - FAR b16_t *regvalue); -static int lm75_writeb16(FAR struct lm75_dev_s *priv, uint8_t regaddr, - b16_t regval); -static int lm75_readtemp(FAR struct lm75_dev_s *priv, FAR b16_t *temp); -static int lm75_readconf(FAR struct lm75_dev_s *priv, FAR uint8_t *conf); -static int lm75_writeconf(FAR struct lm75_dev_s *priv, uint8_t conf); - -/* Character driver methods */ - -static int lm75_open(FAR struct file *filep); -static int lm75_close(FAR struct file *filep); -static ssize_t lm75_read(FAR struct file *, FAR char *, size_t); -static ssize_t lm75_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static int lm75_ioctl(FAR struct file *filep,int cmd,unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations g_lm75fops = -{ - lm75_open, - lm75_close, - lm75_read, - lm75_write, - 0, - lm75_ioctl -#ifndef CONFIG_DISABLE_POLL - , 0 -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ -/**************************************************************************** - * Name: lm75_readb16 - * - * Description: - * Read a 16-bit register (LM75_TEMP_REG, LM75_THYS_REG, or LM75_TOS_REG) - * - ****************************************************************************/ - -static int lm75_readb16(FAR struct lm75_dev_s *priv, uint8_t regaddr, - FAR b16_t *regvalue) -{ - uint8_t buffer[2]; - int ret; - - /* Write the register address */ - - I2C_SETADDRESS(priv->i2c, priv->addr, 7); - ret = I2C_WRITE(priv->i2c, ®addr, 1); - if (ret < 0) - { - lm75dbg("I2C_WRITE failed: %d\n", ret); - return ret; - } - - /* Restart and read 16-bits from the register (discarding 7) */ - - ret = I2C_READ(priv->i2c, buffer, 2); - if (ret < 0) - { - lm75dbg("I2C_READ failed: %d\n", ret); - return ret; - } - - /* Data format is: TTTTTTTT Txxxxxxx where TTTTTTTTT is a nine-bit, - * signed temperature value with LSB = 0.5 degrees centigrade. So the - * raw data is b8_t - */ - - *regvalue = b8tob16((b8_t)buffer[0] << 8 | (b8_t)buffer[1]); - lm75dbg("addr: %02x value: %08x ret: %d\n", regaddr, *regvalue, ret); - return OK; -} - -/**************************************************************************** - * Name: lm75_writeb16 - * - * Description: - * Write to a 16-bit register (LM75_TEMP_REG, LM75_THYS_REG, or LM75_TOS_REG) - * - ****************************************************************************/ - -static int lm75_writeb16(FAR struct lm75_dev_s *priv, uint8_t regaddr, - b16_t regval) -{ - uint8_t buffer[3]; - b8_t regb8; - - lm75dbg("addr: %02x value: %08x\n", regaddr, regval); - - /* Set up a 3 byte message to send */ - - buffer[0] = regaddr; - - regb8 = b16tob8(regval); - buffer[1] = (uint8_t)(regb8 >> 8); - buffer[2] = (uint8_t)regb8; - - /* Write the register address followed by the data (no RESTART) */ - - I2C_SETADDRESS(priv->i2c, priv->addr, 7); - return I2C_WRITE(priv->i2c, buffer, 3); -} - -/**************************************************************************** - * Name: lm75_readtemp - * - * Description: - * Read the temperature register with special scaling (LM75_TEMP_REG) - * - ****************************************************************************/ - -static int lm75_readtemp(FAR struct lm75_dev_s *priv, FAR b16_t *temp) -{ - b16_t temp16; - int ret; - - /* Read the raw temperature data (b16_t) */ - - ret = lm75_readb16(priv, LM75_TEMP_REG, &temp16); - if (ret < 0) - { - lm75dbg("lm75_readb16 failed: %d\n", ret); - return ret; - } - lm75dbg("Centigrade: %08x\n", temp16); - - /* Was fahrenheit requested? */ - - if (priv->fahrenheit) - { - /* Centigrade to Fahrenheit conversion: F = 9*C/5 + 32 */ - - temp16 = b16mulb16(temp16, B16_9DIV5) + B16_32; - lm75dbg("Fahrenheit: %08x\n", temp16); - } - - *temp = temp16; - return OK; -} - -/**************************************************************************** - * Name: lm75_readconf - * - * Description: - * Read the 8-bit LM75 configuration register - * - ****************************************************************************/ - -static int lm75_readconf(FAR struct lm75_dev_s *priv, FAR uint8_t *conf) -{ - uint8_t buffer; - int ret; - - /* Write the configuration register address */ - - I2C_SETADDRESS(priv->i2c, priv->addr, 7); - - buffer = LM75_CONF_REG; - ret = I2C_WRITE(priv->i2c, &buffer, 1); - if (ret < 0) - { - lm75dbg("I2C_WRITE failed: %d\n", ret); - return ret; - } - - /* Restart and read 8-bits from the register */ - - ret = I2C_READ(priv->i2c, conf, 1); - lm75dbg("conf: %02x ret: %d\n", *conf, ret); - return ret; -} - -/**************************************************************************** - * Name: lm75_writeconf - * - * Description: - * Write to a 8-bit LM75 configuration register. - * - ****************************************************************************/ - -static int lm75_writeconf(FAR struct lm75_dev_s *priv, uint8_t conf) -{ - uint8_t buffer[2]; - - lm75dbg("conf: %02x\n", conf); - - /* Set up a 2 byte message to send */ - - buffer[0] = LM75_CONF_REG; - buffer[1] = conf; - - /* Write the register address followed by the data (no RESTART) */ - - I2C_SETADDRESS(priv->i2c, priv->addr, 7); - return I2C_WRITE(priv->i2c, buffer, 2); -} - -/**************************************************************************** - * Name: lm75_open - * - * Description: - * This function is called whenever the LM-75 device is opened. - * - ****************************************************************************/ - -static int lm75_open(FAR struct file *filep) -{ - return OK; -} - -/**************************************************************************** - * Name: lm75_close - * - * Description: - * This routine is called when the LM-75 device is closed. - * - ****************************************************************************/ - -static int lm75_close(FAR struct file *filep) -{ - return OK; -} - -/**************************************************************************** - * Name: lm75_read - ****************************************************************************/ - -static ssize_t lm75_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct lm75_dev_s *priv = inode->i_private; - FAR b16_t *ptr; - ssize_t nsamples; - int i; - int ret; - - /* How many samples were requested to get? */ - - nsamples = buflen / sizeof(b16_t); - ptr = (FAR b16_t *)buffer; - - lm75dbg("buflen: %d nsamples: %d\n", buflen, nsamples); - - /* Get the requested number of samples */ - - for (i = 0; i < nsamples; i++) - { - b16_t temp; - - /* Read the next b16_t temperature value */ - - ret = lm75_readtemp(priv, &temp); - if (ret < 0) - { - lm75dbg("lm75_readtemp failed: %d\n",ret); - return (ssize_t)ret; - } - - /* Save the temperature value in the user buffer */ - - *ptr++ = temp; - } - - return nsamples * sizeof(b16_t); -} - -/**************************************************************************** - * Name: lm75_write - ****************************************************************************/ - -static ssize_t lm75_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen) -{ - return -ENOSYS; -} - -/**************************************************************************** - * Name: lm75_ioctl - ****************************************************************************/ - -static int lm75_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct lm75_dev_s *priv = inode->i_private; - int ret = OK; - - switch (cmd) - { - /* Read from the configuration register. Arg: uint8_t* pointer */ - - case SNIOC_READCONF: - { - FAR uint8_t *ptr = (FAR uint8_t *)((uintptr_t)arg); - ret = lm75_readconf(priv, ptr); - lm75dbg("conf: %02x ret: %d\n", *ptr, ret); - } - break; - - /* Wrtie to the configuration register. Arg: uint8_t value */ - - case SNIOC_WRITECONF: - ret = lm75_writeconf(priv, (uint8_t)arg); - lm75dbg("conf: %02x ret: %d\n", *(uint8_t*)arg, ret); - break; - - /* Shutdown the LM75, Arg: None */ - - case SNIOC_SHUTDOWN: - { - uint8_t conf; - ret = lm75_readconf(priv, &conf); - if (ret == OK) - { - ret = lm75_writeconf(priv, conf | LM75_CONF_SHUTDOWN); - } - lm75dbg("conf: %02x ret: %d\n", conf | LM75_CONF_SHUTDOWN, ret); - } - break; - - /* Powerup the LM75, Arg: None */ - - case SNIOC_POWERUP: - { - uint8_t conf; - ret = lm75_readconf(priv, &conf); - if (ret == OK) - { - ret = lm75_writeconf(priv, conf & ~LM75_CONF_SHUTDOWN); - } - lm75dbg("conf: %02x ret: %d\n", conf & ~LM75_CONF_SHUTDOWN, ret); - } - break; - - /* Report samples in Fahrenheit */ - - case SNIOC_FAHRENHEIT: - priv->fahrenheit = true; - lm75dbg("Fahrenheit\n"); - break; - - /* Report Samples in Centigrade */ - - case SNIOC_CENTIGRADE: - priv->fahrenheit = false; - lm75dbg("Centigrade\n"); - break; - - /* Read THYS temperature register. Arg: b16_t* pointer */ - - case SNIOC_READTHYS: - { - FAR b16_t *ptr = (FAR b16_t *)((uintptr_t)arg); - ret = lm75_readb16(priv, LM75_THYS_REG, ptr); - lm75dbg("THYS: %08x ret: %d\n", *ptr, ret); - } - break; - - /* Write THYS temperature register. Arg: b16_t value */ - - case SNIOC_WRITETHYS: - ret = lm75_writeb16(priv, LM75_THYS_REG, (b16_t)arg); - lm75dbg("THYS: %08x ret: %d\n", (b16_t)arg, ret); - break; - - /* Read TOS (Over-temp Shutdown Threshold) Register. Arg: b16_t* pointer */ - - case SNIOC_READTOS: - { - FAR b16_t *ptr = (FAR b16_t *)((uintptr_t)arg); - ret = lm75_readb16(priv, LM75_TOS_REG, ptr); - lm75dbg("TOS: %08x ret: %d\n", *ptr, ret); - } - break; - - /* Write TOS (Over-temp Shutdown Threshold) Register. Arg: b16_t value */ - - case SNIOC_WRITRETOS: - ret = lm75_writeb16(priv, LM75_TOS_REG, (b16_t)arg); - lm75dbg("TOS: %08x ret: %d\n", (b16_t)arg, ret); - break; - - default: - lm75dbg("Unrecognized cmd: %d\n", cmd); - ret = -ENOTTY; - break; - } - - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: lm75_register - * - * Description: - * Register the LM-75 character device as 'devpath' - * - * Input Parameters: - * devpath - The full path to the driver to register. E.g., "/dev/temp0" - * i2c - An instance of the I2C interface to use to communicate with LM75 - * addr - The I2C address of the LM-75. The base I2C address of the LM75 - * is 0x48. Bits 0-3 can be controlled to get 8 unique addresses from 0x48 - * through 0x4f. - * - * Returned Value: - * Zero (OK) on success; a negated errno value on failure. - * - ****************************************************************************/ - -int lm75_register(FAR const char *devpath, FAR struct i2c_dev_s *i2c, uint8_t addr) -{ - FAR struct lm75_dev_s *priv; - int ret; - - /* Initialize the LM-75 device structure */ - - priv = (FAR struct lm75_dev_s *)malloc(sizeof(struct lm75_dev_s)); - if (!priv) - { - lm75dbg("Failed to allocate instance\n"); - return -ENOMEM; - } - - priv->i2c = i2c; - priv->addr = addr; - priv->fahrenheit = false; - - /* Register the character driver */ - - ret = register_driver(devpath, &g_lm75fops, 0666, priv); - if (ret < 0) - { - lm75dbg("Failed to register driver: %d\n", ret); - free(priv); - } - return ret; -} -#endif /* CONFIG_I2C && CONFIG_I2C_LM75 */ diff --git a/nuttx/drivers/sensors/qencoder.c b/nuttx/drivers/sensors/qencoder.c deleted file mode 100644 index a56adec9a..000000000 --- a/nuttx/drivers/sensors/qencoder.c +++ /dev/null @@ -1,402 +0,0 @@ -/**************************************************************************** - * drivers/sensors/qencoder.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Compilation Switches - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef CONFIG_QENCODER - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Debug ********************************************************************/ -/* Non-standard debug that may be enabled just for testing PWM */ - -#ifdef CONFIG_DEBUG_QENCODER -# define qedbg dbg -# define qevdbg vdbg -# define qelldbg lldbg -# define qellvdbg llvdbg -#else -# define qedbg(x...) -# define qevdbg(x...) -# define qelldbg(x...) -# define qellvdbg(x...) -#endif - -/**************************************************************************** - * Private Type Definitions - ****************************************************************************/ - -/* This structure describes the state of the upper half drivere */ - -struct qe_upperhalf_s -{ - uint8_t crefs; /* The number of times the device has been opened */ - sem_t exclsem; /* Supports mutual exclusion */ - FAR struct qe_lowerhalf_s *lower; /* lower-half state */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int qe_open(FAR struct file *filep); -static int qe_close(FAR struct file *filep); -static ssize_t qe_read(FAR struct file *filep, FAR char *buffer, size_t buflen); -static ssize_t qe_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static int qe_ioctl(FAR struct file *filep, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations g_qeops = -{ - qe_open, /* open */ - qe_close, /* close */ - qe_read, /* read */ - qe_write, /* write */ - 0, /* seek */ - qe_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/************************************************************************************ - * Name: qe_open - * - * Description: - * This function is called whenever the PWM device is opened. - * - ************************************************************************************/ - -static int qe_open(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct qe_upperhalf_s *upper = inode->i_private; - uint8_t tmp; - int ret; - - qevdbg("crefs: %d\n", upper->crefs); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - ret = -errno; - goto errout; - } - - /* Increment the count of references to the device. If this the first - * time that the driver has been opened for this device, then initialize - * the device. - */ - - tmp = upper->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* Check if this is the first time that the driver has been opened. */ - - if (tmp == 1) - { - FAR struct qe_lowerhalf_s *lower = upper->lower; - - /* Yes.. perform one time hardware initialization. */ - - DEBUGASSERT(lower->ops->setup != NULL); - qevdbg("calling setup\n"); - - ret = lower->ops->setup(lower); - if (ret < 0) - { - goto errout_with_sem; - } - } - - /* Save the new open count on success */ - - upper->crefs = tmp; - ret = OK; - -errout_with_sem: - sem_post(&upper->exclsem); - -errout: - return ret; -} - -/************************************************************************************ - * Name: qe_close - * - * Description: - * This function is called when the PWM device is closed. - * - ************************************************************************************/ - -static int qe_close(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct qe_upperhalf_s *upper = inode->i_private; - int ret; - - qevdbg("crefs: %d\n", upper->crefs); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - ret = -errno; - goto errout; - } - - /* Decrement the references to the driver. If the reference count will - * decrement to 0, then uninitialize the driver. - */ - - if (upper->crefs > 1) - { - upper->crefs--; - } - else - { - FAR struct qe_lowerhalf_s *lower = upper->lower; - - /* There are no more references to the port */ - - upper->crefs = 0; - - /* Disable the PWM device */ - - DEBUGASSERT(lower->ops->shutdown != NULL); - qevdbg("calling shutdown: %d\n"); - - lower->ops->shutdown(lower); - } - ret = OK; - -//errout_with_sem: - sem_post(&upper->exclsem); - -errout: - return ret; -} - -/************************************************************************************ - * Name: qe_read - * - * Description: - * A dummy read method. This is provided only to satsify the VFS layer. - * - ************************************************************************************/ - -static ssize_t qe_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - /* Return zero -- usually meaning end-of-file */ - - return 0; -} - -/************************************************************************************ - * Name: qe_write - * - * Description: - * A dummy write method. This is provided only to satsify the VFS layer. - * - ************************************************************************************/ - -static ssize_t qe_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) -{ - /* Return a failure */ - - return -EPERM; -} - -/************************************************************************************ - * Name: qe_ioctl - * - * Description: - * The standard ioctl method. This is where ALL of the PWM work is done. - * - ************************************************************************************/ - -static int qe_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct qe_upperhalf_s *upper = inode->i_private; - FAR struct qe_lowerhalf_s *lower = upper->lower; - int ret; - - qevdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(upper && lower); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - return ret; - } - - /* Handle built-in ioctl commands */ - - switch (cmd) - { - /* QEIOC_POSITION - Get the current position from the encoder. - * Argument: int32_t pointer to the location to return the position. - */ - - case QEIOC_POSITION: - { - FAR int32_t *ptr = (FAR int32_t *)((uintptr_t)arg); - DEBUGASSERT(lower->ops->position != NULL && ptr); - ret = lower->ops->position(lower, ptr); - } - break; - - /* QEIOC_RESET - Reset the position to zero. - * Argument: None - */ - - case QEIOC_RESET: - { - DEBUGASSERT(lower->ops->reset != NULL); - ret = lower->ops->reset(lower); - } - break; - - /* Any unrecognized IOCTL commands might be platform-specific ioctl commands */ - - default: - { - qevdbg("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(lower->ops->ioctl != NULL); - ret = lower->ops->ioctl(lower, cmd, arg); - } - break; - } - - sem_post(&upper->exclsem); - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: qe_register - * - * Description: - * Register the Quadrature Encoder lower half device as 'devpath' - * - * Input Parameters: - * devpath - The full path to the driver to register. E.g., "/dev/qe0" - * lower - An instance of the lower half interface - * - * Returned Value: - * Zero (OK) on success; a negated errno value on failure. The following - * possible error values may be returned (most are returned by - * register_driver()): - * - * EINVAL - 'path' is invalid for this operation - * EEXIST - An inode already exists at 'path' - * ENOMEM - Failed to allocate in-memory resources for the operation - * - ****************************************************************************/ - -int qe_register(FAR const char *devpath, FAR struct qe_lowerhalf_s *lower) -{ - FAR struct qe_upperhalf_s *upper; - - /* Allocate the upper-half data structure */ - - upper = (FAR struct qe_upperhalf_s *)zalloc(sizeof(struct qe_upperhalf_s)); - if (!upper) - { - qedbg("Allocation failed\n"); - return -ENOMEM; - } - - /* Initialize the PWM device structure (it was already zeroed by zalloc()) */ - - sem_init(&upper->exclsem, 0, 1); - upper->lower = lower; - - /* Register the PWM device */ - - qevdbg("Registering %s\n", devpath); - return register_driver(devpath, &g_qeops, 0666, upper); -} - -#endif /* CONFIG_QENCODER */ diff --git a/nuttx/drivers/sercomm/Kconfig b/nuttx/drivers/sercomm/Kconfig deleted file mode 100644 index ae2bf3130..000000000 --- a/nuttx/drivers/sercomm/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# diff --git a/nuttx/drivers/sercomm/Make.defs b/nuttx/drivers/sercomm/Make.defs deleted file mode 100644 index 0cf93d4c8..000000000 --- a/nuttx/drivers/sercomm/Make.defs +++ /dev/null @@ -1,55 +0,0 @@ -############################################################################ -# drivers/serial/Make.defs -# -# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# File descriptor support is needed for this driver - -ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) - -# The sercomm driver should not be build for all platforms. Only build it -# is so configured - -ifeq ($(CONFIG_SERCOMM_CONSOLE),y) - -# Include serial drivers - -CSRCS += console.c uart.c - -# Include sercomm build support - -DEPPATH += --dep-path sercomm -VPATH += :sercomm - -endif -endif diff --git a/nuttx/drivers/sercomm/README.txt b/nuttx/drivers/sercomm/README.txt deleted file mode 100644 index a9239a204..000000000 --- a/nuttx/drivers/sercomm/README.txt +++ /dev/null @@ -1,19 +0,0 @@ -drivers/sercomm README -====================== - -If CONFIG_SERCOMM_CONSOLE is defined in the NuttX configuration file, NuttX -will attempt to use sercomm (HDLC protocol) to communicate with the -host system. Sercomm is the transport used by osmocom-bb that runs on top -of serial. See http://bb.osmocom.org/trac/wiki/nuttx-bb/run for detailed -the usage of nuttx with sercomm. - -The drivers/sercomm build that you have the osmocom-bb project directory -at same level as the nuttx project: - - |- nuttx - |- apps - `- osmocom-bb - -If you attempt to build this driver without osmocom-bb, you will get -compilation errors because ofheader files that are needed from the -osmocom-bb directory. diff --git a/nuttx/drivers/sercomm/console.c b/nuttx/drivers/sercomm/console.c deleted file mode 100644 index 3d038af7c..000000000 --- a/nuttx/drivers/sercomm/console.c +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************** - * drivers/sercomm/console.c - * Driver for NuttX Console - * - * (C) 2010 by Harald Welte - * (C) 2011 Stefan Richter - * - * This source code is derivated from Osmocom-BB project and was - * relicensed as BSD with permission from original authors. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************/ - -#include -#include -#include -#include - -#include -#include -#include - -#include "uart.h" -#include - -/* stubs to make serial driver happy */ -void sercomm_recvchars(void *a) { } -void sercomm_xmitchars(void *a) { } - -/* Stubs to make memory allocator happy */ -void cons_puts(void *foo){} -void delay_ms(int ms){} - -/************************************************************************************ - * Fileops Prototypes and Structures - ************************************************************************************/ - -typedef FAR struct file file_t; - -static ssize_t sc_console_read(file_t *filep, FAR char *buffer, size_t buflen); -static ssize_t sc_console_write(file_t *filep, FAR const char *buffer, size_t buflen); -static int sc_console_ioctl(file_t *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int sc_console_poll(file_t *filep, FAR struct pollfd *fds, bool setup); -#endif - -static const struct file_operations g_sercom_console_ops = -{ - 0, /* open, always opened */ - 0, /* close, stays open */ - sc_console_read, /* read */ - sc_console_write, /* write */ - 0, /* seek, not supported */ - sc_console_ioctl, /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - sc_console_poll /* poll */ -#endif -}; - -/**************************************************************************** - * Helper functions - ****************************************************************************/ -static FAR uart_dev_t *readdev = NULL; -static struct msgb *recvmsg = NULL; -static void recv_cb(uint8_t dlci, struct msgb *msg) -{ - sem_post(&readdev->recvsem); - recvmsg = msg; -} - -/**************************************************************************** - * Fileops - ****************************************************************************/ - -/* XXX: recvmsg is overwritten when multiple msg arrive! */ -static ssize_t sc_console_read(file_t *filep, FAR char *buffer, size_t buflen) -{ - size_t len; - struct msgb *tmp; - - /* Wait until data is received */ - while(recvmsg == NULL) { - sem_wait(&readdev->recvsem); - } - - len = recvmsg->len > buflen ? buflen : recvmsg->len; - memcpy(buffer, msgb_get(recvmsg, len), len); - - if(recvmsg->len == 0) { - /* prevent inconsistent msg by first invalidating it, then free it */ - tmp = recvmsg; - recvmsg = NULL; - msgb_free(tmp); - } - - return len; -} - -/* XXX: redirect to old Osmocom-BB comm/sercomm_cons.c -> 2 buffers */ -extern int sercomm_puts(const char *s); -static ssize_t sc_console_write(file_t *filep, FAR const char *buffer, size_t buflen) -{ - int i, cnt; - char dstbuf[32]; - - if (buflen >= 31) - cnt = 31; - else - cnt = buflen; - - memcpy(dstbuf, buffer, cnt); - dstbuf[cnt] = '\0'; - - /* print part of our buffer */ - sercomm_puts(dstbuf); - - /* wait a little bit to get data transfered */ - up_mdelay(1); - - return cnt; -} - -/* Forward ioctl to uart driver */ -static int sc_console_ioctl(struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR uart_dev_t *dev = inode->i_private; - - return dev->ops->ioctl(filep, cmd, arg); -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/* Use sercomm on uart driver, register console driver */ -int sercomm_register(FAR const char *path, FAR uart_dev_t *dev) -{ - /* XXX: initialize MODEMUART to be used for sercomm*/ - uart_init(SERCOMM_UART_NR, 1); - uart_baudrate(SERCOMM_UART_NR, UART_115200); - readdev = dev; - sercomm_register_rx_cb(SC_DLCI_LOADER, &recv_cb); - - sem_init(&dev->xmit.sem, 0, 1); - sem_init(&dev->recv.sem, 0, 1); - sem_init(&dev->closesem, 0, 1); - sem_init(&dev->xmitsem, 0, 0); - sem_init(&dev->recvsem, 0, 0); -#ifndef CONFIG_DISABLE_POLL - sem_init(&dev->pollsem, 0, 1); -#endif - - dbg("Registering %s\n", path); - return register_driver(path, &g_sercom_console_ops, 0666, NULL); -} diff --git a/nuttx/drivers/sercomm/loadwriter.py b/nuttx/drivers/sercomm/loadwriter.py deleted file mode 100644 index 6234d6f0d..000000000 --- a/nuttx/drivers/sercomm/loadwriter.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python -from socket import * -import time - -SOCKET_NAME = '/tmp/osmocom_loader' - -s = socket(AF_UNIX, SOCK_STREAM) -s.connect(SOCKET_NAME) - -while 1: - try: - x = raw_input(">") - y = len(x) + 1 - s.send(chr(y>>8) + chr(y&255) + x + "\n") - except: - print '' - break - -s.close() diff --git a/nuttx/drivers/sercomm/uart.c b/nuttx/drivers/sercomm/uart.c deleted file mode 100644 index 691bba9ec..000000000 --- a/nuttx/drivers/sercomm/uart.c +++ /dev/null @@ -1,469 +0,0 @@ -/**************************************************************************** - * drivers/sercomm/uart.c - * Calypso DBB internal UART Driver - * - * (C) 2010 by Harald Welte - * (C) 2010 by Ingo Albrecht - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************/ - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -//#include -#include - -#include "uart.h" - -#define BASE_ADDR_UART_MODEM 0xffff5000 -#define OFFSET_IRDA 0x800 - -#define UART_REG(n,m) (BASE_ADDR_UART_MODEM + ((n)*OFFSET_IRDA)+(m)) - -#define LCR7BIT 0x80 -#define LCRBFBIT 0x40 -#define MCR6BIT 0x20 -#define REG_OFFS(m) ((m) & ~(LCR7BIT|LCRBFBIT|MCR6BIT)) -/* read access LCR[7] = 0 */ -enum uart_reg { - RHR = 0, - IER = 1, - IIR = 2, - LCR = 3, - MCR = 4, - LSR = 5, - MSR = 6, - SPR = 7, - MDR1 = 8, - DMR2 = 9, - SFLSR = 0x0a, - RESUME = 0x0b, - SFREGL = 0x0c, - SFREGH = 0x0d, - BLR = 0x0e, - ACREG = 0x0f, - SCR = 0x10, - SSR = 0x11, - EBLR = 0x12, -/* read access LCR[7] = 1 */ - DLL = RHR | LCR7BIT, - DLH = IER | LCR7BIT, - DIV1_6 = ACREG | LCR7BIT, -/* read/write access LCR[7:0] = 0xbf */ - EFR = IIR | LCRBFBIT, - XON1 = MCR | LCRBFBIT, - XON2 = LSR | LCRBFBIT, - XOFF1 = MSR | LCRBFBIT, - XOFF2 = SPR | LCRBFBIT, -/* read/write access if EFR[4] = 1 and MCR[6] = 1 */ - TCR = MSR | MCR6BIT, - TLR = SPR | MCR6BIT, -}; -/* write access LCR[7] = 0 */ -#define THR RHR -#define FCR IIR /* only if EFR[4] = 1 */ -#define TXFLL SFLSR -#define TXFLH RESUME -#define RXFLL SFREGL -#define RXFLH SFREGH - -enum fcr_bits { - FIFO_EN = (1 << 0), - RX_FIFO_CLEAR = (1 << 1), - TX_FIFO_CLEAR = (1 << 2), - DMA_MODE = (1 << 3), -}; -#define TX_FIFO_TRIG_SHIFT 4 -#define RX_FIFO_TRIG_SHIFT 6 - -enum iir_bits { - IIR_INT_PENDING = 0x01, - IIR_INT_TYPE = 0x3E, - IIR_INT_TYPE_RX_STATUS_ERROR = 0x06, - IIR_INT_TYPE_RX_TIMEOUT = 0x0C, - IIR_INT_TYPE_RHR = 0x04, - IIR_INT_TYPE_THR = 0x02, - IIR_INT_TYPE_MSR = 0x00, - IIR_INT_TYPE_XOFF = 0x10, - IIR_INT_TYPE_FLOW = 0x20, - IIR_FCR0_MIRROR = 0xC0, -}; - -#define UART_REG_UIR 0xffff6000 - -/* enable or disable the divisor latch for access to DLL, DLH */ -static void uart_set_lcr7bit(int uart, int on) -{ - uint8_t reg; - - reg = readb(UART_REG(uart, LCR)); - if (on) - reg |= (1 << 7); - else - reg &= ~(1 << 7); - writeb(reg, UART_REG(uart, LCR)); -} - -static uint8_t old_lcr; -static void uart_set_lcr_bf(int uart, int on) -{ - if (on) { - old_lcr = readb(UART_REG(uart, LCR)); - writeb(0xBF, UART_REG(uart, LCR)); - } else { - writeb(old_lcr, UART_REG(uart, LCR)); - } -} - -/* Enable or disable the TCR_TLR latch bit in MCR[6] */ -static void uart_set_mcr6bit(int uart, int on) -{ - uint8_t mcr; - /* we assume EFR[4] is always set to 1 */ - mcr = readb(UART_REG(uart, MCR)); - if (on) - mcr |= (1 << 6); - else - mcr &= ~(1 << 6); - writeb(mcr, UART_REG(uart, MCR)); -} - -static void uart_reg_write(int uart, enum uart_reg reg, uint8_t val) -{ - if (reg & LCRBFBIT) - uart_set_lcr_bf(uart, 1); - else if (reg & LCR7BIT) - uart_set_lcr7bit(uart, 1); - else if (reg & MCR6BIT) - uart_set_mcr6bit(uart, 1); - - writeb(val, UART_REG(uart, REG_OFFS(reg))); - - if (reg & LCRBFBIT) - uart_set_lcr_bf(uart, 0); - else if (reg & LCR7BIT) - uart_set_lcr7bit(uart, 0); - else if (reg & MCR6BIT) - uart_set_mcr6bit(uart, 0); -} - -/* read from a UART register, applying any required latch bits */ -static uint8_t uart_reg_read(int uart, enum uart_reg reg) -{ - uint8_t ret; - - if (reg & LCRBFBIT) - uart_set_lcr_bf(uart, 1); - else if (reg & LCR7BIT) - uart_set_lcr7bit(uart, 1); - else if (reg & MCR6BIT) - uart_set_mcr6bit(uart, 1); - - ret = readb(UART_REG(uart, REG_OFFS(reg))); - - if (reg & LCRBFBIT) - uart_set_lcr_bf(uart, 0); - else if (reg & LCR7BIT) - uart_set_lcr7bit(uart, 0); - else if (reg & MCR6BIT) - uart_set_mcr6bit(uart, 0); - - return ret; -} - -#if 0 -static void uart_irq_handler_cons(__unused enum irq_nr irqnr) -{ - const uint8_t uart = CONS_UART_NR; - uint8_t iir; - - //uart_putchar_nb(uart, 'U'); - - iir = uart_reg_read(uart, IIR); - if (iir & IIR_INT_PENDING) - return; - - switch (iir & IIR_INT_TYPE) { - case IIR_INT_TYPE_RHR: - break; - case IIR_INT_TYPE_THR: - if (cons_rb_flush() == 1) { - /* everything was flushed, disable THR IRQ */ - uint8_t ier = uart_reg_read(uart, IER); - ier &= ~(1 << 1); - uart_reg_write(uart, IER, ier); - } - break; - case IIR_INT_TYPE_MSR: - break; - case IIR_INT_TYPE_RX_STATUS_ERROR: - break; - case IIR_INT_TYPE_RX_TIMEOUT: - break; - case IIR_INT_TYPE_XOFF: - break; - } -} -#endif - -static void uart_irq_handler_sercomm(__unused enum irq_nr irqnr, __unused void *context) -{ - const uint8_t uart = SERCOMM_UART_NR; - uint8_t iir, ch; - - //uart_putchar_nb(uart, 'U'); - - iir = uart_reg_read(uart, IIR); - if (iir & IIR_INT_PENDING) - return; - - switch (iir & IIR_INT_TYPE) { - case IIR_INT_TYPE_RX_TIMEOUT: - case IIR_INT_TYPE_RHR: - /* as long as we have rx data available */ - while (uart_getchar_nb(uart, &ch)) { - if (sercomm_drv_rx_char(ch) < 0) { - /* sercomm cannot receive more data right now */ - uart_irq_enable(uart, UART_IRQ_RX_CHAR, 0); - } - } - break; - case IIR_INT_TYPE_THR: - /* as long as we have space in the FIFO */ - while (!uart_tx_busy(uart)) { - /* get a byte from sercomm */ - if (!sercomm_drv_pull(&ch)) { - /* no more bytes in sercomm, stop TX interrupts */ - uart_irq_enable(uart, UART_IRQ_TX_EMPTY, 0); - break; - } - /* write the byte into the TX FIFO */ - uart_putchar_nb(uart, ch); - } - break; - case IIR_INT_TYPE_MSR: - printf("UART IRQ MSR\n"); - break; - case IIR_INT_TYPE_RX_STATUS_ERROR: - printf("UART IRQ RX_SE\n"); - break; - case IIR_INT_TYPE_XOFF: - printf("UART IRQXOFF\n"); - break; - } -} - -static const uint8_t uart2irq[] = { - [0] = IRQ_UART_IRDA, - [1] = IRQ_UART_MODEM, -}; - -void uart_init(uint8_t uart, uint8_t interrupts) -{ - uint8_t irq = uart2irq[uart]; - - uart_reg_write(uart, IER, 0x00); - - if (uart == SERCOMM_UART_NR) { - sercomm_init(); - irq_attach(IRQ_UART_MODEM, (xcpt_t)uart_irq_handler_sercomm); - up_enable_irq(IRQ_UART_MODEM); - uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1); - } - -#if 0 - if (uart == CONS_UART_NR) { - cons_init(); - if(interrupts) { - irq_register_handler(irq, &uart_irq_handler_cons); - irq_config(irq, 0, 0, 0xff); - irq_enable(irq); - } - } else { - sercomm_init(); - if(interrupts) { - irq_register_handler(irq, &uart_irq_handler_sercomm); - irq_config(irq, 0, 0, 0xff); - irq_enable(irq); - } - uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1); - } -#endif -#if 0 - if (uart == 1) { - /* assign UART to MCU and unmask interrupts*/ - writeb(UART_REG_UIR, 0x00); - } -#endif - - /* if we don't initialize these, we get strange corruptions in the - received data... :-( */ - uart_reg_write(uart, MDR1, 0x07); /* turn off UART */ - uart_reg_write(uart, XON1, 0x00); /* Xon1/Addr Register */ - uart_reg_write(uart, XON2, 0x00); /* Xon2/Addr Register */ - uart_reg_write(uart, XOFF1, 0x00); /* Xoff1 Register */ - uart_reg_write(uart, XOFF2, 0x00); /* Xoff2 Register */ - uart_reg_write(uart, EFR, 0x00); /* Enhanced Features Register */ - - /* select UART mode */ - uart_reg_write(uart, MDR1, 0); - /* no XON/XOFF flow control, ENHANCED_EN, no auto-RTS/CTS */ - uart_reg_write(uart, EFR, (1 << 4)); - /* enable Tx/Rx FIFO, Tx trigger at 56 spaces, Rx trigger at 60 chars */ - uart_reg_write(uart, FCR, FIFO_EN | RX_FIFO_CLEAR | TX_FIFO_CLEAR | - (3 << TX_FIFO_TRIG_SHIFT) | (3 << RX_FIFO_TRIG_SHIFT)); - - /* THR interrupt only when TX FIFO and TX shift register are empty */ - uart_reg_write(uart, SCR, (1 << 0));// | (1 << 3)); - - /* 8 bit, 1 stop bit, no parity, no break */ - uart_reg_write(uart, LCR, 0x03); - - uart_set_lcr7bit(uart, 0); -} - -void uart_poll(uint8_t uart) { -/* if(uart == CONS_UART_NR) { - uart_irq_handler_cons(0); - } else -*/ { - uart_irq_handler_sercomm(0, NULL); - } -} - -void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on) -{ - uint8_t ier = uart_reg_read(uart, IER); - uint8_t mask = 0; - - switch (irq) { - case UART_IRQ_TX_EMPTY: - mask = (1 << 1); - break; - case UART_IRQ_RX_CHAR: - mask = (1 << 0); - break; - } - - if (on) - ier |= mask; - else - ier &= ~mask; - - uart_reg_write(uart, IER, ier); -} - - -void uart_putchar_wait(uint8_t uart, int c) -{ - /* wait while TX FIFO indicates full */ - while (readb(UART_REG(uart, SSR)) & 0x01) { } - - /* put character in TX FIFO */ - writeb(c, UART_REG(uart, THR)); -} - -int uart_putchar_nb(uint8_t uart, int c) -{ - /* if TX FIFO indicates full, abort */ - if (readb(UART_REG(uart, SSR)) & 0x01) - return 0; - - writeb(c, UART_REG(uart, THR)); - return 1; -} - -int uart_getchar_nb(uint8_t uart, uint8_t *ch) -{ - uint8_t lsr; - - lsr = readb(UART_REG(uart, LSR)); - - /* something strange happened */ - if (lsr & 0x02) - printf("LSR RX_OE\n"); - if (lsr & 0x04) - printf("LSR RX_PE\n"); - if (lsr & 0x08) - printf("LSR RX_FE\n"); - if (lsr & 0x10) - printf("LSR RX_BI\n"); - if (lsr & 0x80) - printf("LSR RX_FIFO_STS\n"); - - /* is the Rx FIFO empty? */ - if (!(lsr & 0x01)) - return 0; - - *ch = readb(UART_REG(uart, RHR)); - //printf("getchar_nb(%u) = %02x\n", uart, *ch); - return 1; -} - -int uart_tx_busy(uint8_t uart) -{ - if (readb(UART_REG(uart, SSR)) & 0x01) - return 1; - return 0; -} - -static const uint16_t divider[] = { - [UART_38400] = 21, /* 38,690 */ - [UART_57600] = 14, /* 58,035 */ - [UART_115200] = 7, /* 116,071 */ - [UART_230400] = 4, /* 203,125! (-3% would be 223,488) */ - [UART_460800] = 2, /* 406,250! (-3% would be 446,976) */ - [UART_921600] = 1, /* 812,500! (-3% would be 893,952) */ -}; - -int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt) -{ - uint16_t div; - - if (bdrt > ARRAY_SIZE(divider)) - return -1; - - div = divider[bdrt]; - uart_set_lcr7bit(uart, 1); - writeb(div & 0xff, UART_REG(uart, DLL)); - writeb(div >> 8, UART_REG(uart, DLH)); - uart_set_lcr7bit(uart, 0); - - return 0; -} diff --git a/nuttx/drivers/sercomm/uart.h b/nuttx/drivers/sercomm/uart.h deleted file mode 100644 index 81d7a1560..000000000 --- a/nuttx/drivers/sercomm/uart.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _UART_H -#define _UART_H - -#include - -enum uart_baudrate { - UART_38400, - UART_57600, - UART_115200, - UART_230400, - UART_460800, - UART_614400, - UART_921600, -}; - -void uart_init(uint8_t uart, uint8_t interrupts); -void uart_putchar_wait(uint8_t uart, int c); -int uart_putchar_nb(uint8_t uart, int c); -int uart_getchar_nb(uint8_t uart, uint8_t *ch); -int uart_tx_busy(uint8_t uart); -int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt); - -enum uart_irq { - UART_IRQ_TX_EMPTY, - UART_IRQ_RX_CHAR, -}; - -void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on); - -void uart_poll(uint8_t uart); - -#endif /* _UART_H */ diff --git a/nuttx/drivers/serial/Kconfig b/nuttx/drivers/serial/Kconfig deleted file mode 100644 index 119923a69..000000000 --- a/nuttx/drivers/serial/Kconfig +++ /dev/null @@ -1,1054 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config DEV_LOWCONSOLE - bool "Low-level console support" - default n - depends on ARCH_LOWPUTC - ---help--- - Use the simple, low-level, write-only serial console driver (minimal support) - -config SERIAL_REMOVABLE - bool - -config 16550_UART - bool "16550 UART Chip support" - default n - -if 16550_UART -config 16550_UART0 - bool "16550 UART0" - default n - -if 16550_UART0 -config 16550_UART0_BASE - hex "16550 UART0 base address" - -config 16550_UART0_CLOCK - int "16550 UART0 clock" - -config 16550_UART0_IRQ - int "16550 UART0 IRQ number" - -config 16550_UART0_BAUD - int "16550 UART0 BAUD" - default 115200 - -config 16550_UART0_PARITY - int "16550 UART0 parity" - default 0 - ---help--- - 16550 UART0 parity. 0=None, 1=Odd, 2=Even. Default: None - -config 16550_UART0_BITS - int "16550 UART0 number of bits" - default 8 - ---help--- - 16550 UART0 number of bits. Default: 8 - -config 16550_UART0_2STOP - int "16550 UART0 two stop bits" - default 0 - ---help--- - 0=1 stop bit, 1=Two stop bits. Default: 1 stop bit - -config 16550_UART0_RXBUFSIZE - int "16550 UART0 Rx buffer size" - default 256 - ---help--- - 16550 UART0 Rx buffer size. Default: 256 - -config 16550_UART0_TXBUFSIZE - int "16550 UART0 Tx buffer size" - default 256 - ---help--- - 16550 UART0 Tx buffer size. Default: 256 - -endif - -config 16550_UART1 - bool "16550 UART1" - default n - -if 16550_UART1 -config 16550_UART1_BASE - hex "16550 UART1 base address" - -config 16550_UART1_CLOCK - int "16550 UART1 clock" - -config 16550_UART1_IRQ - int "16550 UART1 IRQ number" - -config 16550_UART1_BAUD - int "16550 UART1 BAUD" - default 115200 - -config 16550_UART1_PARITY - int "16550 UART1 parity" - default 0 - ---help--- - 16550 UART1 parity. 0=None, 1=Odd, 2=Even. Default: None - -config 16550_UART1_BITS - int "16550 UART1 number of bits" - default 8 - ---help--- - 16550 UART1 number of bits. Default: 8 - -config 16550_UART1_2STOP - int "16550 UART1 two stop bits" - default 0 - ---help--- - 0=1 stop bit, 1=Two stop bits. Default: 1 stop bit - -config 16550_UART1_RXBUFSIZE - int "16550 UART1 Rx buffer size" - default 256 - ---help--- - 16550 UART1 Rx buffer size. Default: 256 - -config 16550_UART1_TXBUFSIZE - int "16550 UART1 Tx buffer size" - default 256 - ---help--- - 16550 UART1 Tx buffer size. Default: 256 - -endif - -config 16550_UART2 - bool "16550 UART2" - default n - -if 16550_UART2 -config 16550_UART2_BASE - hex "16550 UART2 base address" - -config 16550_UART2_CLOCK - int "16550 UART2 clock" - -config 16550_UART2_IRQ - int "16550 UART2 IRQ number" - -config 16550_UART2_BAUD - int "16550 UART2 BAUD" - default 115200 - -config 16550_UART2_PARITY - int "16550 UART2 parity" - default 0 - ---help--- - 16550 UART2 parity. 0=None, 1=Odd, 2=Even. Default: None - -config 16550_UART2_BITS - int "16550 UART2 number of bits" - default 8 - ---help--- - 16550 UART2 number of bits. Default: 8 - -config 16550_UART2_2STOP - int "16550 UART2 two stop bits" - default 0 - ---help--- - 0=1 stop bit, 1=Two stop bits. Default: 1 stop bit - -config 16550_UART2_RXBUFSIZE - int "16550 UART2 Rx buffer size" - default 256 - ---help--- - 16550 UART2 Rx buffer size. Default: 256 - -config 16550_UART2_TXBUFSIZE - int "16550 UART2 Tx buffer size" - default 256 - ---help--- - 16550 UART2 Tx buffer size. Default: 256 - -endif - -config 16550_UART3 - bool "16550 UART3" - default n - -if 16550_UART3 -config 16550_UART3_BASE - hex "16550 UART3 base address" - -config 16550_UART3_CLOCK - int "16550 UART3 clock" - -config 16550_UART3_IRQ - int "16550 UART3 IRQ number" - -config 16550_UART3_BAUD - int "16550 UART3 BAUD" - default 115200 - -config 16550_UART3_PARITY - int "16550 UART3 parity" - default 0 - ---help--- - 16550 UART3 parity. 0=None, 1=Odd, 2=Even. Default: None - -config 16550_UART3_BITS - int "16550 UART3 number of bits" - default 8 - ---help--- - 16550 UART3 number of bits. Default: 8 - -config 16550_UART3_2STOP - int "16550 UART3 two stop bits" - default 0 - ---help--- - 0=1 stop bit, 1=Two stop bits. Default: 1 stop bit - -config 16550_UART3_RXBUFSIZE - int "16550 UART3 Rx buffer size" - default 256 - ---help--- - 16550 UART3 Rx buffer size. Default: 256 - -config 16550_UART3_TXBUFSIZE - int "16550 UART3 Tx buffer size" - default 256 - ---help--- - 16550 UART3 Tx buffer size. Default: 256 - -endif - -choice - prompt "16550 Serial Console" - default 16550_NO_SERIAL_CONSOLE - -config 16550_UART0_SERIAL_CONSOLE - bool "16550 UART0 serial console" - depends on 16550_UART0 - -config 16550_UART1_SERIAL_CONSOLE - bool "16550 UART1 serial console" - depends on 16550_UART1 - -config 16550_UART2_SERIAL_CONSOLE - bool "16550 UART2 serial console" - depends on 16550_UART2 - -config 16550_UART3_SERIAL_CONSOLE - bool "16550 UART3 serial console" - depends on 16550_UART3 - -config 16550_NO_SERIAL_CONSOLE - bool "No 16550 serial console" - -endchoice - -config 16550_SUPRESS_CONFIG - bool "Suppress 16550 configuration" - default n - ---help--- - This option is useful, for example, if you are using a bootloader - that configures the 16550_UART. In that case, you may want to - just leave the existing console configuration in place. Default: n - -config 16550_REGINCR - int "Address increment between 16550 registers" - default 1 - ---help--- - The address increment between 16550 registers. Options are 1, 2, or 4. - Default: 1 - -config 16550_REGWIDTH - int "Bit width of 16550 registers" - default 8 - ---help--- - The bit width of registers. Options are 8, 16, or 32. Default: 8 - -config 16550_ADDRWIDTH - int "Address width of 16550 registers" - default 8 - ---help--- - The bit width of registers. Options are 8, 16, or 32. Default: 8 - -endif - -# -# MCU serial peripheral driver? -# - -config ARCH_HAVE_UART - bool -config ARCH_HAVE_UART0 - bool -config ARCH_HAVE_UART1 - bool -config ARCH_HAVE_UART2 - bool -config ARCH_HAVE_UART3 - bool -config ARCH_HAVE_UART4 - bool -config ARCH_HAVE_UART5 - bool -config ARCH_HAVE_UART6 - bool - -config ARCH_HAVE_USART0 - bool -config ARCH_HAVE_USART1 - bool -config ARCH_HAVE_USART2 - bool -config ARCH_HAVE_USART3 - bool -config ARCH_HAVE_USART4 - bool -config ARCH_HAVE_USART5 - bool -config ARCH_HAVE_USART6 - bool - -config MCU_SERIAL - bool - default y if ARCH_HAVE_UART || ARCH_HAVE_UART0 || ARCH_HAVE_USART0 || ARCH_HAVE_UART1 || ARCH_HAVE_USART1 || \ - ARCH_HAVE_UART2 || ARCH_HAVE_USART2 || ARCH_HAVE_UART3 || ARCH_HAVE_USART3 || \ - ARCH_HAVE_UART4 || ARCH_HAVE_USART4 || ARCH_HAVE_UART5 || ARCH_HAVE_USART5 || ARCH_HAVE_UART6 || ARCH_HAVE_USART6 - -# -# Standard serial driver configuration -# - -config STANDARD_SERIAL - bool "Enable standard \"upper-half\" serial driver" - default y if MCU_SERIAL - default n if !MCU_SERIAL - depends on !DEV_LOWCONSOLE - ---help--- - Enable the standard, upper-half serial driver used by most MCU serial peripherals. - -config CONFIG_SERIAL_NPOLLWAITERS - int "Number of poll threads" - default 2 - depends on !DISABLE_POLL && STANDARD_SERIAL - ---help--- - Maximum number of threads than can be waiting for POLL events. - Default: 2 - -# -# U[S]ARTn_XYZ settings for MCU serial drivers -# - -choice - prompt "Serial console" - depends on MCU_SERIAL - default NO_SERIAL_CONSOLE - -config UART_SERIAL_CONSOLE - bool "UART" - depends on ARCH_HAVE_UART - -config UART0_SERIAL_CONSOLE - bool "UART0" - depends on ARCH_HAVE_UART0 - -config USART0_SERIAL_CONSOLE - bool "USART0" - depends on ARCH_HAVE_USART0 - -config UART1_SERIAL_CONSOLE - bool "UART1" - depends on ARCH_HAVE_UART1 - -config USART1_SERIAL_CONSOLE - bool "USART1" - depends on ARCH_HAVE_USART1 - -config UART2_SERIAL_CONSOLE - bool "UART2" - depends on ARCH_HAVE_UART2 - -config USART2_SERIAL_CONSOLE - bool "USART2" - depends on ARCH_HAVE_USART2 - -config UART3_SERIAL_CONSOLE - bool "UART3" - depends on ARCH_HAVE_UART3 - -config USART3_SERIAL_CONSOLE - bool "USART3" - depends on ARCH_HAVE_USART3 - -config UART4_SERIAL_CONSOLE - bool "UART4" - depends on ARCH_HAVE_UART4 - -config USART4_SERIAL_CONSOLE - bool "USART4" - depends on ARCH_HAVE_USART4 - -config UART5_SERIAL_CONSOLE - bool "UART5" - depends on ARCH_HAVE_UART5 - -config USART5_SERIAL_CONSOLE - bool "USART5" - depends on ARCH_HAVE_USART5 - -config UART6_SERIAL_CONSOLE - bool "UART6" - depends on ARCH_HAVE_UART6 - -config USART6_SERIAL_CONSOLE - bool "USART6" - depends on ARCH_HAVE_USART6 - -config NO_SERIAL_CONSOLE - bool "No serial console" - -endchoice - -menu "UART Configuration" - depends on ARCH_HAVE_UART - -config UART_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART_2STOP - int "use 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "UART0 Configuration" - depends on ARCH_HAVE_UART0 - -config UART0_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART0_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART0_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART0_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART0_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART0_2STOP - int "use 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "USART0 Configuration" - depends on ARCH_HAVE_USART0 - -config USART0_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config USART0_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config USART0_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the USART. - -config USART0_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config USART0_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config USART0_2STOP - int "use 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "UART1 Configuration" - depends on ARCH_HAVE_UART1 - -config UART1_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART1_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART1_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART1_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART1_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART1_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "USART1 Configuration" - depends on ARCH_HAVE_USART1 - -config USART1_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config USART1_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config USART1_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the USART. - -config USART1_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config USART1_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config USART1_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "UART2 Configuration" - depends on ARCH_HAVE_UART2 - -config UART2_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART2_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART2_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART2_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART2_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART2_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "USART2 Configuration" - depends on ARCH_HAVE_USART2 - -config USART2_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config USART2_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config USART2_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the USART. - -config USART2_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config USART2_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config USART2_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "UART3 Configuration" - depends on ARCH_HAVE_UART3 - -config UART3_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART3_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART3_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART3_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART3_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART3_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "USART3 Configuration" - depends on ARCH_HAVE_USART3 - -config USART3_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config USART3_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config USART3_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the USART. - -config USART3_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config USART3_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config USART3_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "UART4 Configuration" - depends on ARCH_HAVE_UART4 - -config UART4_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART4_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART4_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART4_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART4_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART4_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "USART4 Configuration" - depends on ARCH_HAVE_USART4 - -config USART4_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config USART4_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config USART4_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the USART. - -config USART4_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config USART4_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config USART4_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "UART5 Configuration" - depends on ARCH_HAVE_UART5 - -config UART5_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART5_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART5_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART5_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART5_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART5_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "USART5 Configuration" - depends on ARCH_HAVE_USART5 - -config USART5_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config USART5_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config USART5_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the USART. - -config USART5_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config USART5_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config USART5_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "USART6 Configuration" - depends on ARCH_HAVE_USART6 - -config USART6_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config USART6_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config USART6_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the USART. - -config USART6_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config USART6_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config USART6_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu - -menu "UART6 Configuration" - depends on ARCH_HAVE_UART6 - -config UART6_RXBUFSIZE - int "receive buffer size" - default 256 - help - Characters are buffered as they are received. This specifies - the size of the receive buffer. - -config UART6_TXBUFSIZE - int "transmit buffer size" - default 256 - help - Characters are buffered before being sent. This specifies - the size of the transmit buffer. - -config UART6_BAUD - int "baud rate" - default 115200 - help - The configured BAUD of the UART. - -config UART6_BITS - int "character size" - default 8 - help - The number of bits. Must be either 7 or 8. - -config UART6_PARITY - int "parity setting" - default 0 - help - 0=no parity, 1=odd parity, 2=even parity - -config UART6_2STOP - int "uses 2 stop bits" - default 0 - help - 1=Two stop bits - -endmenu diff --git a/nuttx/drivers/serial/Make.defs b/nuttx/drivers/serial/Make.defs deleted file mode 100644 index b99f4eb36..000000000 --- a/nuttx/drivers/serial/Make.defs +++ /dev/null @@ -1,50 +0,0 @@ -############################################################################ -# drivers/serial/Make.defs -# -# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) - -# Include serial drivers - -CSRCS += serial.c serialirq.c lowconsole.c - -ifeq ($(CONFIG_16550_UART),y) - CSRCS += uart_16550.c -endif - -# Include serial build support - -DEPPATH += --dep-path serial -VPATH += :serial -endif diff --git a/nuttx/drivers/serial/lowconsole.c b/nuttx/drivers/serial/lowconsole.c deleted file mode 100644 index 1fac49a57..000000000 --- a/nuttx/drivers/serial/lowconsole.c +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** - * drivers/serial/lowconsole.c - * - * Copyright (C) 2008-2009, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* The architecture must provide up_putc for this driver */ - -#ifndef CONFIG_ARCH_LOWPUTC -# error "Architecture must provide up_putc() for this driver" -#endif - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static ssize_t lowconsole_read(struct file *filep, char *buffer, size_t buflen); -static ssize_t lowconsole_write(struct file *filep, const char *buffer, size_t buflen); -static int lowconsole_ioctl(struct file *filep, int cmd, unsigned long arg); - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -static const struct file_operations g_consoleops = -{ - 0, /* open */ - 0, /* close */ - lowconsole_read, /* read */ - lowconsole_write, /* write */ - 0, /* seek */ - lowconsole_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: lowconsole_ioctl - ****************************************************************************/ - -static int lowconsole_ioctl(struct file *filep, int cmd, unsigned long arg) -{ - return -ENOTTY; -} - -/**************************************************************************** - * Name: lowconsole_read - ****************************************************************************/ - -static ssize_t lowconsole_read(struct file *filep, char *buffer, size_t buflen) -{ - return 0; -} - -/**************************************************************************** - * Name: lowconsole_write - ****************************************************************************/ - -static ssize_t lowconsole_write(struct file *filep, const char *buffer, size_t buflen) -{ - ssize_t ret = buflen; - - for (; buflen; buflen--) - { - up_putc(*buffer++); - } - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: lowconsole_init -****************************************************************************/ - -void lowconsole_init(void) -{ - (void)register_driver("/dev/console", &g_consoleops, 0666, NULL); -} diff --git a/nuttx/drivers/serial/serial.c b/nuttx/drivers/serial/serial.c deleted file mode 100644 index 0fed1d6c5..000000000 --- a/nuttx/drivers/serial/serial.c +++ /dev/null @@ -1,1377 +0,0 @@ -/************************************************************************************ - * drivers/serial/serial.c - * - * Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/************************************************************************************ - * Definitions - ************************************************************************************/ - -/* The architecture must provide up_putc for this driver */ - -#ifndef CONFIG_ARCH_LOWPUTC -# error "Architecture must provide up_putc() for this driver" -#endif - -#define uart_putc(ch) up_putc(ch) - -#define HALF_SECOND_MSEC 500 -#define HALF_SECOND_USEC 500000L - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -static int uart_open(FAR struct file *filep); -static int uart_close(FAR struct file *filep); -static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen); -static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); -static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); -#endif - -/************************************************************************************ - * Private Variables - ************************************************************************************/ - -static const struct file_operations g_serialops = -{ - uart_open, /* open */ - uart_close, /* close */ - uart_read, /* read */ - uart_write, /* write */ - 0, /* seek */ - uart_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , uart_poll /* poll */ -#endif -}; - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: uart_takesem - ************************************************************************************/ - -static int uart_takesem(FAR sem_t *sem, bool errout) -{ - /* Loop, ignoring interrupts, until we have successfully acquired the semaphore */ - - while (sem_wait(sem) != OK) - { - /* The only case that an error should occur here is if the wait was awakened - * by a signal. - */ - - ASSERT(get_errno() == EINTR); - - /* When the signal is received, should we errout? Or should we just continue - * waiting until we have the semaphore? - */ - - if (errout) - { - return -EINTR; - } - } - - return OK; -} - -/************************************************************************************ - * Name: uart_givesem - ************************************************************************************/ - -#define uart_givesem(sem) (void)sem_post(sem) - -/**************************************************************************** - * Name: uart_pollnotify - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static void uart_pollnotify(FAR uart_dev_t *dev, pollevent_t eventset) -{ - int i; - - for (i = 0; i < CONFIG_SERIAL_NPOLLWAITERS; i++) - { - struct pollfd *fds = dev->fds[i]; - if (fds) - { -#ifdef CONFIG_SERIAL_REMOVABLE - fds->revents |= ((fds->events | (POLLERR|POLLHUP)) & eventset); -#else - fds->revents |= (fds->events & eventset); -#endif - if (fds->revents != 0) - { - fvdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } - } -} -#else -# define uart_pollnotify(dev,event) -#endif - -/************************************************************************************ - * Name: uart_putxmitchar - ************************************************************************************/ - -static int uart_putxmitchar(FAR uart_dev_t *dev, int ch) -{ - irqstate_t flags; - int nexthead; - int ret; - - /* Increment to see what the next head pointer will be. We need to use the "next" - * head pointer to determine when the circular buffer would overrun - */ - - nexthead = dev->xmit.head + 1; - if (nexthead >= dev->xmit.size) - { - nexthead = 0; - } - - /* Loop until we are able to add the character to the TX buffer */ - - for (;;) - { - if (nexthead != dev->xmit.tail) - { - dev->xmit.buffer[dev->xmit.head] = ch; - dev->xmit.head = nexthead; - return OK; - } - else - { - /* Inform the interrupt level logic that we are waiting. This and - * the following steps must be atomic. - */ - - flags = irqsave(); - -#ifdef CONFIG_SERIAL_REMOVABLE - /* Check if the removable device is no longer connected while we - * have interrupts off. We do not want the transition to occur - * as a race condition before we begin the wait. - */ - - if (dev->disconnected) - { - irqrestore(flags); - return -ENOTCONN; - } -#endif - /* Wait for some characters to be sent from the buffer with the TX - * interrupt enabled. When the TX interrupt is enabled, uart_xmitchars - * should execute and remove some of the data from the TX buffer. - */ - - dev->xmitwaiting = true; - uart_enabletxint(dev); - ret = uart_takesem(&dev->xmitsem, true); - uart_disabletxint(dev); - irqrestore(flags); - -#ifdef CONFIG_SERIAL_REMOVABLE - /* Check if the removable device was disconnected while we were - * waiting. - */ - - if (dev->disconnected) - { - return -ENOTCONN; - } -#endif - /* Check if we were awakened by signal. */ - - if (ret < 0) - { - /* A signal received while waiting for the xmit buffer to become - * non-full will abort the transfer. - */ - - return -EINTR; - } - } - } - - /* We won't get here. Some compilers may complain that this code is - * unreachable. - */ - - return OK; -} - -/************************************************************************************ - * Name: uart_irqwrite - ************************************************************************************/ - -static inline ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer, size_t buflen) -{ - ssize_t ret = buflen; - - /* Force each character through the low level interface */ - - for (; buflen; buflen--) - { - int ch = *buffer++; - - /* If this is the console, then we should replace LF with CR-LF */ - - if (ch == '\n') - { - uart_putc('\r'); - } - - /* Output the character, using the low-level direct UART interfaces */ - - uart_putc(ch); - } - - return ret; -} - -/************************************************************************************ - * Name: uart_write - ************************************************************************************/ - -static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) -{ - FAR struct inode *inode = filep->f_inode; - FAR uart_dev_t *dev = inode->i_private; - ssize_t nread = buflen; - int ret; - char ch; - - /* We may receive console writes through this path from interrupt handlers and - * from debug output in the IDLE task! In these cases, we will need to do things - * a little differently. - */ - - if (up_interrupt_context() || getpid() == 0) - { -#ifdef CONFIG_SERIAL_REMOVABLE - /* If the removable device is no longer connected, refuse to write to - * the device. - */ - - if (dev->disconnected) - { - return -ENOTCONN; - } -#endif - - /* up_putc() will be used to generate the output in a busy-wait loop. - * up_putc() is only available for the console device. - */ - - if (dev->isconsole) - { - irqstate_t flags = irqsave(); - ret = uart_irqwrite(dev, buffer, buflen); - irqrestore(flags); - return ret; - } - else - { - return -EPERM; - } - } - - /* Only one user can access dev->xmit.head at a time */ - - ret = (ssize_t)uart_takesem(&dev->xmit.sem, true); - if (ret < 0) - { - /* A signal received while waiting for access to the xmit.head will - * abort the transfer. - */ - - return ret; - } - -#ifdef CONFIG_SERIAL_REMOVABLE - /* If the removable device is no longer connected, refuse to write to the - * device. This check occurs after taking the xmit.sem because the - * disconnection event might have occurred while we were waiting for - * access to the transmit buffers. - */ - - if (dev->disconnected) - { - uart_givesem(&dev->xmit.sem); - return -ENOTCONN; - } -#endif - - /* Loop while we still have data to copy to the transmit buffer. - * we add data to the head of the buffer; uart_xmitchars takes the - * data from the end of the buffer. - */ - - uart_disabletxint(dev); - for (; buflen; buflen--) - { - ch = *buffer++; - - /* Do output post-processing */ - -#ifdef CONFIG_SERIAL_TERMIOS - - if (dev->tc_oflag & OPOST) - { - - /* Mapping CR to NL? */ - - if ((ch == '\r') && (dev->tc_oflag & OCRNL)) - { - ch = '\n'; - } - - /* Are we interested in newline processing? */ - - if ((ch == '\n') && (dev->tc_oflag & (ONLCR | ONLRET))) - { - ret = uart_putxmitchar(dev, '\r'); - - if (ret != OK) - { - break; - } - } - - /* Specifically not handled: - * - * OXTABS - primarily a full-screen terminal optimisation - * ONOEOT - Unix interoperability hack - * OLCUC - Not specified by Posix - * ONOCR - low-speed interactive optimisation - */ - - } - -#else /* !CONFIG_SERIAL_TERMIOS */ - - /* If this is the console, convert \n -> \r\n */ - - if (dev->isconsole && ch == '\n') - { - ret = uart_putxmitchar(dev, '\r'); - } - -#endif - - /* Put the character into the transmit buffer */ - - ret = uart_putxmitchar(dev, ch); - - if (ret != OK) - { - break; - } - - } - - if (dev->xmit.head != dev->xmit.tail) - { - uart_enabletxint(dev); - } - - uart_givesem(&dev->xmit.sem); - - /* uart_putxmitchar() might return an error under one of two - * conditions: (1) The wait for buffer space might have been - * interrupted by a signal (ret should be -EINTR), or (2) if - * CONFIG_SERIAL_REMOVABLE is defined, then uart_putxmitchar() - * might also return if the serial device was disconnected - * (wtih -ENOTCONN). - */ - - if (ret < 0) - { - /* POSIX requires that we return -1 and errno set if no data was - * transferred. Otherwise, we return the number of bytes in the - * interrupted transfer. - */ - - if (buflen < nread) - { - /* Some data was transferred. Return the number of bytes that were - * successfully transferred. - */ - - nread -= buflen; - } - else - { - /* No data was transferred. Return the negated error. The VFS layer - * will set the errno value appropriately). - */ - - nread = -ret; - } - } - - return nread; -} - -/************************************************************************************ - * Name: uart_read - ************************************************************************************/ - -static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - FAR struct inode *inode = filep->f_inode; - FAR uart_dev_t *dev = inode->i_private; - irqstate_t flags; - ssize_t recvd = 0; - int16_t tail; - int ret; - char ch; - - /* Only one user can access dev->recv.tail at a time */ - - ret = uart_takesem(&dev->recv.sem, true); - if (ret < 0) - { - /* A signal received while waiting for access to the recv.tail will avort - * the transfer. After the transfer has started, we are committed and - * signals will be ignored. - */ - - return ret; - } - - /* Loop while we still have data to copy to the receive buffer. - * we add data to the head of the buffer; uart_xmitchars takes the - * data from the end of the buffer. - */ - - while (recvd < buflen) - { -#ifdef CONFIG_SERIAL_REMOVABLE - /* If the removable device is no longer connected, refuse to read any - * further from the device. - */ - - if (dev->disconnected) - { - if (recvd == 0) - { - recvd = -ENOTCONN; - } - - break; - } -#endif - - /* Check if there is more data to return in the circular buffer. - * NOTE: Rx interrupt handling logic may aynchronously increment - * the head index but must not modify the tail index. The tail - * index is only modified in this function. Therefore, no - * special handshaking is required here. - * - * The head and tail pointers are 16-bit values. The only time that - * the following could be unsafe is if the CPU made two non-atomic - * 8-bit accesses to obtain the 16-bit head index. - */ - - tail = dev->recv.tail; - if (dev->recv.head != tail) - { - /* Take the next character from the tail of the buffer */ - - ch = dev->recv.buffer[tail]; - - /* Increment the tail index. Most operations are done using the - * local variable 'tail' so that the final dev->recv.tail update - * is atomic. - */ - - if (++tail >= dev->recv.size) - { - tail = 0; - } - - dev->recv.tail = tail; - -#ifdef CONFIG_SERIAL_TERMIOS - - /* Do input processing if any is enabled */ - - if (dev->tc_iflag & (INLCR | IGNCR | ICRNL)) - { - - /* \n -> \r or \r -> \n translation? */ - - if ((ch == '\n') && (dev->tc_iflag & INLCR)) - { - ch = '\r'; - } - else if ((ch == '\r') && (dev->tc_iflag & ICRNL)) - { - ch = '\n'; - } - - /* discarding \r ? */ - if ((ch == '\r') & (dev->tc_iflag & IGNCR)) - { - continue; - } - - } - - /* Specifically not handled: - * - * All of the local modes; echo, line editing, etc. - * Anything to do with break or parity errors. - * ISTRIP - we should be 8-bit clean. - * IUCLC - Not Posix - * IXON/OXOFF - no xon/xoff flow control. - */ - -#endif - - /* store the received character */ - - *buffer++ = ch; - recvd++; - - } - -#ifdef CONFIG_DEV_SERIAL_FULLBLOCKS - /* No... then we would have to wait to get receive more data. - * If the user has specified the O_NONBLOCK option, then just - * return what we have. - */ - - else if (filep->f_oflags & O_NONBLOCK) - { - /* If nothing was transferred, then return the -EAGAIN - * error (not zero which means end of file). - */ - - if (recvd < 1) - { - recvd = -EAGAIN; - } - - break; - } -#else - /* No... the circular buffer is empty. Have we returned anything - * to the caller? - */ - - else if (recvd > 0) - { - /* Yes.. break out of the loop and return the number of bytes - * received up to the wait condition. - */ - - break; - } - - /* No... then we would have to wait to get receive some data. - * If the user has specified the O_NONBLOCK option, then do not - * wait. - */ - - else if (filep->f_oflags & O_NONBLOCK) - { - /* Break out of the loop returning -EAGAIN */ - - recvd = -EAGAIN; - break; - } -#endif - /* Otherwise we are going to have to wait for data to arrive */ - - else - { - /* Disable Rx interrupts and test again... */ - - uart_disablerxint(dev); - - /* If the Rx ring buffer still empty? Bytes may have been addded - * between the last time that we checked and when we disabled Rx - * interrupts. - */ - - if (dev->recv.head == dev->recv.tail) - { - /* Yes.. the buffer is still empty. Wait for some characters - * to be received into the buffer with the RX interrupt re- - * enabled. All interrupts are disabled briefly to assure - * that the following operations are atomic. - */ - - flags = irqsave(); - -#ifdef CONFIG_SERIAL_REMOVABLE - /* Check if the removable device is no longer connected while - * we have interrupts off. We do not want the transition to - * occur as a race condition before we begin the wait. - */ - - if (dev->disconnected) - { - uart_enablerxint(dev); - irqrestore(flags); - ret = -ENOTCONN; - break; - } -#endif - /* Now wait with the Rx interrupt re-enabled. NuttX will - * automatically re-enable global interrupts when this thread - * goes to sleep. - */ - - dev->recvwaiting = true; - uart_enablerxint(dev); - ret = uart_takesem(&dev->recvsem, true); - irqrestore(flags); - - /* Was a signal received while waiting for data to be - * received? Was a removable device disconnected while - * we were waiting? - */ - -#ifdef CONFIG_SERIAL_REMOVABLE - if (ret < 0 || dev->disconnected) -#else - if (ret < 0) -#endif - { - /* POSIX requires that we return after a signal is received. - * If some bytes were read, we need to return the number of bytes - * read; if no bytes were read, we need to return -1 with the - * errno set correctly. - */ - - if (recvd == 0) - { - /* No bytes were read, return -EINTR (the VFS layer will - * set the errno value appropriately. - */ - -#ifdef CONFIG_SERIAL_REMOVABLE - recvd = dev->disconnected ? -ENOTCONN : -EINTR; -#else - recvd = -EINTR; -#endif - } - - break; - } - } - else - { - /* No... the ring buffer is no longer empty. Just re-enable Rx - * interrupts and accept the new data on the next time through - * the loop. - */ - - uart_enablerxint(dev); - } - } - } - - uart_givesem(&dev->recv.sem); - return recvd; -} - -/************************************************************************************ - * Name: uart_ioctl - ************************************************************************************/ - -static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR uart_dev_t *dev = inode->i_private; - - /* Handle TTY-level IOCTLs here */ - /* Let low-level driver handle the call first */ - - int ret = dev->ops->ioctl(filep, cmd, arg); - - /* - * The device ioctl() handler returns -ENOTTY when it doesn't know - * how to handle the command. Check if we can handle it here. - */ - if (ret == -ENOTTY) - { - switch (cmd) - { - - case FIONREAD: - { - int count; - irqstate_t state = irqsave(); - - /* determine the number of bytes available in the buffer */ - - if (dev->recv.tail <= dev->recv.head) - { - count = dev->recv.head - dev->recv.tail; - } - else - { - count = dev->recv.size - (dev->recv.tail - dev->recv.head); - } - - irqrestore(state); - - *(int *)arg = count; - ret = 0; - - break; - } - - case FIONWRITE: - { - int count; - irqstate_t state = irqsave(); - - /* determine the number of bytes free in the buffer */ - - if (dev->xmit.head < dev->xmit.tail) - { - count = dev->xmit.tail - dev->xmit.head - 1; - } - else - { - count = dev->xmit.size - (dev->xmit.head - dev->xmit.tail) - 1; - } - - irqrestore(state); - - *(int *)arg = count; - ret = 0; - - break; - } - } - } - - /* Append any higher level TTY flags */ - - else if (ret == OK) - { - switch (cmd) - { -#ifdef CONFIG_SERIAL_TERMIOS - case TCGETS: - { - struct termios *termiosp = (struct termios*)arg; - - if (!termiosp) - { - ret = -EINVAL; - break; - } - - /* and update with flags from this layer */ - - termiosp->c_iflag = dev->tc_iflag; - termiosp->c_oflag = dev->tc_oflag; - termiosp->c_lflag = dev->tc_lflag; - } - - break; - - case TCSETS: - { - struct termios *termiosp = (struct termios*)arg; - - if (!termiosp) - { - ret = -EINVAL; - break; - } - - /* update the flags we keep at this layer */ - - dev->tc_iflag = termiosp->c_iflag; - dev->tc_oflag = termiosp->c_oflag; - dev->tc_lflag = termiosp->c_lflag; - } - - break; -#endif - } - } - return ret; -} - -/**************************************************************************** - * Name: uart_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) -{ - FAR struct inode *inode = filep->f_inode; - FAR uart_dev_t *dev = inode->i_private; - pollevent_t eventset; - int ndx; - int ret; - int i; - - /* Some sanity checking */ - -#if CONFIG_DEBUG - if (!dev || !fds) - { - return -ENODEV; - } -#endif - - /* Are we setting up the poll? Or tearing it down? */ - - ret = uart_takesem(&dev->pollsem, true); - if (ret < 0) - { - /* A signal received while waiting for access to the poll data - * will abort the operation. - */ - - return ret; - } - - if (setup) - { - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_SERIAL_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!dev->fds[i]) - { - /* Bind the poll structure and this slot */ - - dev->fds[i] = fds; - fds->priv = &dev->fds[i]; - break; - } - } - - if (i >= CONFIG_SERIAL_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? - * First, check if the xmit buffer is full. - * - * Get exclusive access to the xmit buffer indices. NOTE: that we do not - * let this wait be interrupted by a signal (we probably should, but that - * would be a little awkward). - */ - - eventset = 0; - (void)uart_takesem(&dev->xmit.sem, false); - - ndx = dev->xmit.head + 1; - if (ndx >= dev->xmit.size) - { - ndx = 0; - } - - if (ndx != dev->xmit.tail) - { - eventset |= (fds->events & POLLOUT); - } - - uart_givesem(&dev->xmit.sem); - - /* Check if the receive buffer is empty. - * - * Get exclusive access to the recv buffer indices. NOTE: that we do not - * let this wait be interrupted by a signal (we probably should, but that - * would be a little awkward). - */ - - (void)uart_takesem(&dev->recv.sem, false); - if (dev->recv.head != dev->recv.tail) - { - eventset |= (fds->events & POLLIN); - } - - uart_givesem(&dev->recv.sem); - -#ifdef CONFIG_SERIAL_REMOVABLE - /* Check if a removable device has been disconnected. */ - - if (dev->disconnected) - { - eventset |= (POLLERR|POLLHUP); - } -#endif - - if (eventset) - { - uart_pollnotify(dev, eventset); - } - - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - -#ifdef CONFIG_DEBUG - if (!slot) - { - ret = -EIO; - goto errout; - } -#endif - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - uart_givesem(&dev->pollsem); - return ret; -} -#endif - -/************************************************************************************ - * Name: uart_close - * - * Description: - * This routine is called when the serial port gets closed. - * It waits for the last remaining data to be sent. - * - ************************************************************************************/ - -static int uart_close(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR uart_dev_t *dev = inode->i_private; - irqstate_t flags; - - /* Get exclusive access to the close semaphore (to synchronize open/close operations. - * NOTE: that we do not let this wait be interrupted by a signal. Technically, we - * should, but almost no one every checks the return value from close() so we avoid - * a potential memory leak by ignoring signals in this case. - */ - - (void)uart_takesem(&dev->closesem, false); - if (dev->open_count > 1) - { - dev->open_count--; - uart_givesem(&dev->closesem); - return OK; - } - - /* There are no more references to the port */ - - dev->open_count = 0; - - /* Stop accepting input */ - - uart_disablerxint(dev); - - /* Now we wait for the transmit buffer to clear */ - - while (dev->xmit.head != dev->xmit.tail) - { -#ifndef CONFIG_DISABLE_SIGNALS - usleep(HALF_SECOND_USEC); -#else - up_mdelay(HALF_SECOND_MSEC); -#endif - } - - /* And wait for the TX fifo to drain */ - - while (!uart_txempty(dev)) - { -#ifndef CONFIG_DISABLE_SIGNALS - usleep(HALF_SECOND_USEC); -#else - up_mdelay(HALF_SECOND_MSEC); -#endif - } - - /* Free the IRQ and disable the UART */ - - flags = irqsave(); /* Disable interrupts */ - uart_detach(dev); /* Detach interrupts */ - if (!dev->isconsole) /* Check for the serial console UART */ - { - uart_shutdown(dev); /* Disable the UART */ - } - - irqrestore(flags); - - uart_givesem(&dev->closesem); - return OK; - } - -/************************************************************************************ - * Name: uart_open - * - * Description: - * This routine is called whenever a serial port is opened. - * - ************************************************************************************/ - -static int uart_open(FAR struct file *filep) -{ - struct inode *inode = filep->f_inode; - uart_dev_t *dev = inode->i_private; - uint8_t tmp; - int ret; - - /* If the port is the middle of closing, wait until the close is finished. - * If a signal is received while we are waiting, then return EINTR. - */ - - ret = uart_takesem(&dev->closesem, true); - if (ret < 0) - { - /* A signal received while waiting for the last close operation. */ - - return ret; - } - -#ifdef CONFIG_SERIAL_REMOVABLE - /* If the removable device is no longer connected, refuse to open the - * device. We check this after obtaining the close semaphore because - * we might have been waiting when the device was disconnected. - */ - - if (dev->disconnected) - { - ret = -ENOTCONN; - goto errout_with_sem; - } -#endif - - /* Start up serial port */ - /* Increment the count of references to the device. */ - - tmp = dev->open_count + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* Check if this is the first time that the driver has been opened. */ - - if (tmp == 1) - { - irqstate_t flags = irqsave(); - - /* If this is the console, then the UART has already been initialized. */ - - if (!dev->isconsole) - { - /* Perform one time hardware initialization */ - - ret = uart_setup(dev); - if (ret < 0) - { - irqrestore(flags); - goto errout_with_sem; - } - } - - /* In any event, we do have to configure for interrupt driven mode of - * operation. Attach the hardware IRQ(s). Hmm.. should shutdown() the - * the device in the rare case that uart_attach() fails, tmp==1, and - * this is not the console. - */ - - ret = uart_attach(dev); - if (ret < 0) - { - uart_shutdown(dev); - irqrestore(flags); - goto errout_with_sem; - } - - /* Mark the io buffers empty */ - - dev->xmit.head = 0; - dev->xmit.tail = 0; - dev->recv.head = 0; - dev->recv.tail = 0; - - /* initialise termios state */ - -#ifdef CONFIG_SERIAL_TERMIOS - - dev->tc_iflag = 0; - if (dev->isconsole == true) - { - - /* enable \n -> \r\n translation for the console */ - - dev->tc_oflag = OPOST | ONLCR; - } - else - { - dev->tc_oflag = 0; - } - -#endif - - /* Enable the RX interrupt */ - - uart_enablerxint(dev); - irqrestore(flags); - } - - /* Save the new open count on success */ - - dev->open_count = tmp; - -errout_with_sem: - uart_givesem(&dev->closesem); - return ret; -} - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: uart_register - * - * Description: - * Register serial console and serial ports. - * - ************************************************************************************/ - -int uart_register(FAR const char *path, FAR uart_dev_t *dev) -{ - sem_init(&dev->xmit.sem, 0, 1); - sem_init(&dev->recv.sem, 0, 1); - sem_init(&dev->closesem, 0, 1); - sem_init(&dev->xmitsem, 0, 0); - sem_init(&dev->recvsem, 0, 0); -#ifndef CONFIG_DISABLE_POLL - sem_init(&dev->pollsem, 0, 1); -#endif - - /* Setup termios flags */ - -#ifdef CONFIG_SERIAL_TERMIOS - - if (dev->isconsole == true) - { - - /* enable \n -> \r\n translation for the console as early as possible */ - - dev->tc_oflag = OPOST | ONLCR; - dev->tc_iflag = 0; - } - -#endif - - dbg("Registering %s\n", path); - return register_driver(path, &g_serialops, 0666, dev); -} - -/************************************************************************************ - * Name: uart_datareceived - * - * Description: - * This function is called from uart_recvchars when new serial data is place in - * the driver's circular buffer. This function will wake-up any stalled read() - * operations that are waiting for incoming data. - * - ************************************************************************************/ - -void uart_datareceived(FAR uart_dev_t *dev) -{ - /* Is there a thread waiting for read data? */ - - if (dev->recvwaiting) - { - /* Yes... wake it up */ - - dev->recvwaiting = false; - (void)sem_post(&dev->recvsem); - } - - /* Notify all poll/select waiters that they can read from the recv buffer */ - - uart_pollnotify(dev, POLLIN); - -} - -/************************************************************************************ - * Name: uart_datasent - * - * Description: - * This function is called from uart_xmitchars after serial data has been sent, - * freeing up some space in the driver's circular buffer. This function will - * wake-up any stalled write() operations that was waiting for space to buffer - * outgoing data. - * - ************************************************************************************/ - -void uart_datasent(FAR uart_dev_t *dev) -{ - /* Is there a thread waiting for space in xmit.buffer? */ - - if (dev->xmitwaiting) - { - /* Yes... wake it up */ - - dev->xmitwaiting = false; - (void)sem_post(&dev->xmitsem); - } - - /* Notify all poll/select waiters that they can write to xmit buffer */ - - uart_pollnotify(dev, POLLOUT); -} - -/************************************************************************************ - * Name: uart_connected - * - * Description: - * Serial devices (like USB serial) can be removed. In that case, the "upper - * half" serial driver must be informed that there is no longer a valid serial - * channel associated with the driver. - * - * In this case, the driver will terminate all pending transfers wint ENOTCONN and - * will refuse all further transactions while the "lower half" is disconnected. - * The driver will continue to be registered, but will be in an unusable state. - * - * Conversely, the "upper half" serial driver needs to know when the serial - * device is reconnected so that it can resume normal operations. - * - * Assumptions/Limitations: - * This function may be called from an interrupt handler. - * - ************************************************************************************/ - -#ifdef CONFIG_SERIAL_REMOVABLE -void uart_connected(FAR uart_dev_t *dev, bool connected) -{ - irqstate_t flags; - - /* Is the device disconnected? */ - - flags = irqsave(); - dev->disconnected = !connected; - if (!connected) - { - /* Yes.. wake up all waiting threads. Each thread should detect the - * disconnection and return the ENOTCONN error. - */ - - /* Is there a thread waiting for space in xmit.buffer? */ - - if (dev->xmitwaiting) - { - /* Yes... wake it up */ - - dev->xmitwaiting = false; - (void)sem_post(&dev->xmitsem); - } - - /* Is there a thread waiting for read data? */ - - if (dev->recvwaiting) - { - /* Yes... wake it up */ - - dev->recvwaiting = false; - (void)sem_post(&dev->recvsem); - } - - /* Notify all poll/select waiters that and hangup occurred */ - - uart_pollnotify(dev, (POLLERR|POLLHUP)); - } - - irqrestore(flags); -} -#endif - - - diff --git a/nuttx/drivers/serial/serialirq.c b/nuttx/drivers/serial/serialirq.c deleted file mode 100644 index fda5b4afb..000000000 --- a/nuttx/drivers/serial/serialirq.c +++ /dev/null @@ -1,186 +0,0 @@ -/************************************************************************************ - * drivers/serial/serialirq.c - * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/************************************************************************************ - * Private Function Prototypes - ************************************************************************************/ - -/************************************************************************************ - * Private Variables - ************************************************************************************/ - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: uart_xmitchars - * - * Description: - * This function is called from the UART interrupt handler when an interrupt - * is received indicating that there is more space in the transmit FIFO. This - * function will send characters from the tail of the xmit buffer while the driver - * write() logic adds data to the head of the xmit buffer. - * - ************************************************************************************/ - -void uart_xmitchars(FAR uart_dev_t *dev) -{ - uint16_t nbytes = 0; - - /* Send while we still have data & room in the fifo */ - - while (dev->xmit.head != dev->xmit.tail && uart_txready(dev)) - { - /* Send the next byte */ - - uart_send(dev, dev->xmit.buffer[dev->xmit.tail]); - nbytes++; - - /* Increment the tail index */ - - if (++(dev->xmit.tail) >= dev->xmit.size) - { - dev->xmit.tail = 0; - } - } - - /* When all of the characters have been sent from the buffer disable the TX - * interrupt. - */ - - if (dev->xmit.head == dev->xmit.tail) - { - uart_disabletxint(dev); - } - - /* If any bytes were removed from the buffer, inform any waiters there there is - * space available. - */ - - if (nbytes) - { - uart_datasent(dev); - } -} - -/************************************************************************************ - * Name: uart_receivechars - * - * Description: - * This function is called from the UART interrupt handler when an interrupt - * is received indicating that are bytes available in the receive fifo. This - * function will add chars to head of receive buffer. Driver read() logic will - * take characters from the tail of the buffer. - * - ************************************************************************************/ - -void uart_recvchars(FAR uart_dev_t *dev) -{ - unsigned int status; - int nexthead = dev->recv.head + 1; - uint16_t nbytes = 0; - - if (nexthead >= dev->recv.size) - { - nexthead = 0; - } - - /* Loop putting characters into the receive buffer until either there are no - * further characters to available. - */ - - while (uart_rxavailable(dev)) - { - char ch = uart_receive(dev, &status); - - /* If the RX buffer becomes full, then the serial data is discarded. This is - * necessary because on most serial hardware, you must read the data in order - * to clear the RX interrupt. An option on some hardware might be to simply - * disable RX interrupts until the RX buffer becomes non-FULL. However, that - * would probably just cause the overrun to occur in hardware (unless it has - * some large internal buffering). - */ - - if (nexthead != dev->recv.tail) - { - /* Add the character to the buffer */ - - dev->recv.buffer[dev->recv.head] = ch; - nbytes++; - - /* Increment the head index */ - - dev->recv.head = nexthead; - if (++nexthead >= dev->recv.size) - { - nexthead = 0; - } - } - } - - /* If any bytes were added to the buffer, inform any waiters there there is new - * incoming data available. - */ - - if (nbytes) - { - uart_datareceived(dev); - } -} diff --git a/nuttx/drivers/serial/uart_16550.c b/nuttx/drivers/serial/uart_16550.c deleted file mode 100644 index 8fb71bfd2..000000000 --- a/nuttx/drivers/serial/uart_16550.c +++ /dev/null @@ -1,1164 +0,0 @@ -/**************************************************************************** - * drivers/serial/uart_16550.c - * Serial driver for 16550 UART - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_16550_UART - -/**************************************************************************** - * Pre-processor definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct u16550_s -{ - uart_addrwidth_t uartbase; /* Base address of UART registers */ -#ifndef CONFIG_16550_SUPRESS_CONFIG - uint32_t baud; /* Configured baud */ - uint32_t uartclk; /* UART clock frequency */ -#endif -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - uart_datawidth_t ier; /* Saved IER value */ - uint8_t irq; /* IRQ associated with this UART */ -#endif -#ifndef CONFIG_16550_SUPRESS_CONFIG - uint8_t parity; /* 0=none, 1=odd, 2=even */ - uint8_t bits; /* Number of bits (7 or 8) */ - bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int u16550_setup(struct uart_dev_s *dev); -static void u16550_shutdown(struct uart_dev_s *dev); -static int u16550_attach(struct uart_dev_s *dev); -static void u16550_detach(struct uart_dev_s *dev); -#ifndef CONFIG_SUPPRESS_SERIAL_INTS -static int u16550_interrupt(int irq, void *context); -#endif -static int u16550_ioctl(struct file *filep, int cmd, unsigned long arg); -static int u16550_receive(struct uart_dev_s *dev, uint32_t *status); -static void u16550_rxint(struct uart_dev_s *dev, bool enable); -static bool u16550_rxavailable(struct uart_dev_s *dev); -static void u16550_send(struct uart_dev_s *dev, int ch); -static void u16550_txint(struct uart_dev_s *dev, bool enable); -static bool u16550_txready(struct uart_dev_s *dev); -static bool u16550_txempty(struct uart_dev_s *dev); - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -struct uart_ops_s g_uart_ops = -{ - .setup = u16550_setup, - .shutdown = u16550_shutdown, - .attach = u16550_attach, - .detach = u16550_detach, - .ioctl = u16550_ioctl, - .receive = u16550_receive, - .rxint = u16550_rxint, - .rxavailable = u16550_rxavailable, - .send = u16550_send, - .txint = u16550_txint, - .txready = u16550_txready, - .txempty = u16550_txempty, -}; - -/* I/O buffers */ - -#ifdef CONFIG_16550_UART0 -static char g_uart0rxbuffer[CONFIG_16550_UART0_RXBUFSIZE]; -static char g_uart0txbuffer[CONFIG_16550_UART0_TXBUFSIZE]; -#endif -#ifdef CONFIG_16550_UART1 -static char g_uart1rxbuffer[CONFIG_16550_UART1_RXBUFSIZE]; -static char g_uart1txbuffer[CONFIG_16550_UART1_TXBUFSIZE]; -#endif -#ifdef CONFIG_16550_UART2 -static char g_uart2rxbuffer[CONFIG_16550_UART2_RXBUFSIZE]; -static char g_uart2txbuffer[CONFIG_16550_UART2_TXBUFSIZE]; -#endif -#ifdef CONFIG_16550_UART3 -static char g_uart3rxbuffer[CONFIG_16550_UART3_RXBUFSIZE]; -static char g_uart3txbuffer[CONFIG_16550_UART3_TXBUFSIZE]; -#endif - -/* This describes the state of the LPC17xx uart0 port. */ - -#ifdef CONFIG_16550_UART0 -static struct u16550_s g_uart0priv = -{ - .uartbase = CONFIG_16550_UART0_BASE, -#ifndef CONFIG_16550_SUPRESS_CONFIG - .baud = CONFIG_16550_UART0_BAUD, - .uartclk = CONFIG_16550_UART0_CLOCK, -#endif -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - .irq = CONFIG_16550_UART0_IRQ, -#endif -#ifndef CONFIG_16550_SUPRESS_CONFIG - .parity = CONFIG_16550_UART0_PARITY, - .bits = CONFIG_16550_UART0_BITS, - .stopbits2 = CONFIG_16550_UART0_2STOP, -#endif -}; - -static uart_dev_t g_uart0port = -{ - .recv = - { - .size = CONFIG_16550_UART0_RXBUFSIZE, - .buffer = g_uart0rxbuffer, - }, - .xmit = - { - .size = CONFIG_16550_UART0_TXBUFSIZE, - .buffer = g_uart0txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart0priv, -}; -#endif - -/* This describes the state of the LPC17xx uart1 port. */ - -#ifdef CONFIG_16550_UART1 -static struct u16550_s g_uart1priv = -{ - .uartbase = CONFIG_16550_UART1_BASE, -#ifndef CONFIG_16550_SUPRESS_CONFIG - .baud = CONFIG_16550_UART1_BAUD, - .uartclk = CONFIG_16550_UART1_CLOCK, -#endif -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - .irq = CONFIG_16550_UART1_IRQ, -#endif -#ifndef CONFIG_16550_SUPRESS_CONFIG - .parity = CONFIG_16550_UART1_PARITY, - .bits = CONFIG_16550_UART1_BITS, - .stopbits2 = CONFIG_16550_UART1_2STOP, -#endif -}; - -static uart_dev_t g_uart1port = -{ - .recv = - { - .size = CONFIG_16550_UART1_RXBUFSIZE, - .buffer = g_uart1rxbuffer, - }, - .xmit = - { - .size = CONFIG_16550_UART1_TXBUFSIZE, - .buffer = g_uart1txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart1priv, -}; -#endif - -/* This describes the state of the LPC17xx uart1 port. */ - -#ifdef CONFIG_16550_UART2 -static struct u16550_s g_uart2priv = -{ - .uartbase = CONFIG_16550_UART2_BASE, -#ifndef CONFIG_16550_SUPRESS_CONFIG - .baud = CONFIG_16550_UART2_BAUD, - .uartclk = CONFIG_16550_UART2_CLOCK, -#endif -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - .irq = CONFIG_16550_UART2_IRQ, -#endif -#ifndef CONFIG_16550_SUPRESS_CONFIG - .parity = CONFIG_16550_UART2_PARITY, - .bits = CONFIG_16550_UART2_BITS, - .stopbits2 = CONFIG_16550_UART2_2STOP, -#endif -}; - -static uart_dev_t g_uart2port = -{ - .recv = - { - .size = CONFIG_16550_UART2_RXBUFSIZE, - .buffer = g_uart2rxbuffer, - }, - .xmit = - { - .size = CONFIG_16550_UART2_TXBUFSIZE, - .buffer = g_uart2txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart2priv, -}; -#endif - -/* This describes the state of the LPC17xx uart1 port. */ - -#ifdef CONFIG_16550_UART3 -static struct u16550_s g_uart3priv = -{ - .uartbase = CONFIG_16550_UART3_BASE, -#ifndef CONFIG_16550_SUPRESS_CONFIG - .baud = CONFIG_16550_UART3_BAUD, - .uartclk = CONFIG_16550_UART3_CLOCK, -#endif -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - .irq = CONFIG_16550_UART3_IRQ, -#endif -#ifndef CONFIG_16550_SUPRESS_CONFIG - .parity = CONFIG_16550_UART3_PARITY, - .bits = CONFIG_16550_UART3_BITS, - .stopbits2 = CONFIG_16550_UART3_2STOP, -#endif -}; - -static uart_dev_t g_uart3port = -{ - .recv = - { - .size = CONFIG_16550_UART3_RXBUFSIZE, - .buffer = g_uart3rxbuffer, - }, - .xmit = - { - .size = CONFIG_16550_UART3_TXBUFSIZE, - .buffer = g_uart3txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart3priv, -}; -#endif - -/* Which UART with be tty0/console and which tty1? tty2? tty3? */ - -#if defined(CONFIG_16550_UART0_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart0port /* UART0=console */ -# define TTYS0_DEV g_uart0port /* UART0=ttyS0 */ -# ifdef CONFIG_16550_UART1 -# define TTYS1_DEV g_uart1port /* UART0=ttyS0;UART1=ttyS1 */ -# ifdef CONFIG_16550_UART2 -# define TTYS2_DEV g_uart2port /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS2 */ -# ifdef CONFIG_16550_UART3 -# define TTYS3_DEV g_uart3port /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS2;UART3=ttyS3 */ -# else -# undef TTYS3_DEV /* UART0=ttyS0;UART1=ttyS1;UART2=ttyS;No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART3 -# define TTYS2_DEV g_uart3port /* UART0=ttyS0;UART1=ttyS1;UART3=ttys2;No ttyS3 */ -# else -# undef TTYS2_DEV /* UART0=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART2 -# define TTYS1_DEV g_uart2port /* UART0=ttyS0;UART2=ttyS1;No ttyS3 */ -# ifdef CONFIG_16550_UART3 -# define TTYS2_DEV g_uart3port /* UART0=ttyS0;UART2=ttyS1;UART3=ttyS2;No ttyS3 */ -# else -# undef TTYS2_DEV /* UART0=ttyS0;UART2=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# else -# ifdef CONFIG_16550_UART3 -# define TTYS1_DEV g_uart3port /* UART0=ttyS0;UART3=ttyS1;No ttyS2;No ttyS3 */ -# else -# undef TTYS1_DEV /* UART0=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS2_DEV /* No ttyS2 */ -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# endif -#elif defined(CONFIG_16550_UART1_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart1port /* UART1=console */ -# define TTYS0_DEV g_uart1port /* UART1=ttyS0 */ -# ifdef CONFIG_16550_UART -# define TTYS1_DEV g_uart0port /* UART1=ttyS0;UART0=ttyS1 */ -# ifdef CONFIG_16550_UART2 -# define TTYS2_DEV g_uart2port /* UART1=ttyS0;UART0=ttyS1;UART2=ttyS2 */ -# ifdef CONFIG_16550_UART3 -# define TTYS3_DEV g_uart3port /* UART1=ttyS0;UART0=ttyS1;UART2=ttyS2;UART3=ttyS3 */ -# else -# undef TTYS3_DEV /* UART1=ttyS0;UART0=ttyS1;UART2=ttyS;No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART3 -# define TTYS2_DEV g_uart3port /* UART1=ttyS0;UART0=ttyS1;UART3=ttys2;No ttyS3 */ -# else -# undef TTYS2_DEV /* UART1=ttyS0;UART0=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART2 -# define TTYS1_DEV g_uart2port /* UART1=ttyS0;UART2=ttyS1 */ -# ifdef CONFIG_16550_UART3 -# define TTYS2_DEV g_uart3port /* UART1=ttyS0;UART2=ttyS1;UART3=ttyS2;No ttyS3 */ -# else -# undef TTYS2_DEV /* UART1=ttyS0;UART2=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# else -# ifdef CONFIG_16550_UART3 -# define TTYS1_DEV g_uart3port /* UART1=ttyS0;UART3=ttyS1;No ttyS2;No ttyS3 */ -# else -# undef TTYS1_DEV /* UART1=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS2_DEV /* No ttyS2 */ -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# endif -#elif defined(CONFIG_16550_UART2_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart2port /* UART2=console */ -# define TTYS0_DEV g_uart2port /* UART2=ttyS0 */ -# ifdef CONFIG_16550_UART -# define TTYS1_DEV g_uart0port /* UART2=ttyS0;UART0=ttyS1 */ -# ifdef CONFIG_16550_UART1 -# define TTYS2_DEV g_uart1port /* UART2=ttyS0;UART0=ttyS1;UART1=ttyS2 */ -# ifdef CONFIG_16550_UART3 -# define TTYS3_DEV g_uart3port /* UART2=ttyS0;UART0=ttyS1;UART1=ttyS2;UART3=ttyS3 */ -# else -# undef TTYS3_DEV /* UART2=ttyS0;UART0=ttyS1;UART1=ttyS;No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART3 -# define TTYS2_DEV g_uart3port /* UART2=ttyS0;UART0=ttyS1;UART3=ttys2;No ttyS3 */ -# else -# undef TTYS2_DEV /* UART2=ttyS0;UART0=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART1 -# define TTYS1_DEV g_uart1port /* UART2=ttyS0;UART1=ttyS1 */ -# ifdef CONFIG_16550_UART3 -# define TTYS2_DEV g_uart3port /* UART2=ttyS0;UART1=ttyS1;UART3=ttyS2 */ -# else -# undef TTYS2_DEV /* UART2=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# else -# ifdef CONFIG_16550_UART3 -# define TTYS1_DEV g_uart3port /* UART2=ttyS0;UART3=ttyS1;No ttyS3 */ -# else -# undef TTYS1_DEV /* UART2=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS2_DEV /* No ttyS2 */ -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# endif -#elif defined(CONFIG_16550_UART3_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart3port /* UART3=console */ -# define TTYS0_DEV g_uart3port /* UART3=ttyS0 */ -# ifdef CONFIG_16550_UART -# define TTYS1_DEV g_uart0port /* UART3=ttyS0;UART0=ttyS1 */ -# ifdef CONFIG_16550_UART1 -# define TTYS2_DEV g_uart1port /* UART3=ttyS0;UART0=ttyS1;UART1=ttyS2 */ -# ifdef CONFIG_16550_UART2 -# define TTYS3_DEV g_uart2port /* UART3=ttyS0;UART0=ttyS1;UART1=ttyS2;UART2=ttyS3 */ -# else -# undef TTYS3_DEV /* UART3=ttyS0;UART0=ttyS1;UART1=ttyS;No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART2 -# define TTYS2_DEV g_uart2port /* UART3=ttyS0;UART0=ttyS1;UART2=ttys2;No ttyS3 */ -# else -# undef TTYS2_DEV /* UART3=ttyS0;UART0=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# else -# ifdef CONFIG_16550_UART1 -# define TTYS1_DEV g_uart1port /* UART3=ttyS0;UART1=ttyS1 */ -# ifdef CONFIG_16550_UART2 -# define TTYS2_DEV g_uart2port /* UART3=ttyS0;UART1=ttyS1;UART2=ttyS2;No ttyS3 */ -# else -# undef TTYS2_DEV /* UART3=ttyS0;UART1=ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS3_DEV /* No ttyS3 */ -# else -# ifdef CONFIG_16550_UART2 -# define TTYS1_DEV g_uart2port /* UART3=ttyS0;UART2=ttyS1;No ttyS3;No ttyS3 */ -# undef TTYS3_DEV /* UART3=ttyS0;UART2=ttyS1;No ttyS2;No ttyS3 */ -# else -# undef TTYS1_DEV /* UART3=ttyS0;No ttyS1;No ttyS2;No ttyS3 */ -# endif -# undef TTYS2_DEV /* No ttyS2 */ -# undef TTYS3_DEV /* No ttyS3 */ -# endif -# endif -#endif - -/************************************************************************************ - * Inline Functions - ************************************************************************************/ - -/**************************************************************************** - * Name: u16550_serialin - ****************************************************************************/ - -static inline uart_datawidth_t u16550_serialin(struct u16550_s *priv, int offset) -{ - return uart_getreg(priv->uartbase, offset); -} - -/**************************************************************************** - * Name: u16550_serialout - ****************************************************************************/ - -static inline void u16550_serialout(struct u16550_s *priv, int offset, uart_datawidth_t value) -{ - uart_putreg(priv->uartbase, offset, value); -} - -/**************************************************************************** - * Name: u16550_disableuartint - ****************************************************************************/ - -#ifndef CONFIG_SUPPRESS_SERIAL_INTS -static inline void u16550_disableuartint(struct u16550_s *priv, uart_datawidth_t *ier) -{ - if (ier) - { - *ier = priv->ier & UART_IER_ALLIE; - } - - priv->ier &= ~UART_IER_ALLIE; - u16550_serialout(priv, UART_IER_OFFSET, priv->ier); -} -#else -# define u16550_disableuartint(priv,ier) -#endif - -/**************************************************************************** - * Name: u16550_restoreuartint - ****************************************************************************/ - -#ifndef CONFIG_SUPPRESS_SERIAL_INTS -static inline void u16550_restoreuartint(struct u16550_s *priv, uint32_t ier) -{ - priv->ier |= ier & UART_IER_ALLIE; - u16550_serialout(priv, UART_IER_OFFSET, priv->ier); -} -#else -# define u16550_restoreuartint(priv,ier) -#endif - -/**************************************************************************** - * Name: u16550_enablebreaks - ****************************************************************************/ - -static inline void u16550_enablebreaks(struct u16550_s *priv, bool enable) -{ - uint32_t lcr = u16550_serialin(priv, UART_LCR_OFFSET); - if (enable) - { - lcr |= UART_LCR_BRK; - } - else - { - lcr &= ~UART_LCR_BRK; - } - u16550_serialout(priv, UART_LCR_OFFSET, lcr); -} - -/************************************************************************************ - * Name: u16550_divisor - * - * Descrption: - * Select a divider to produce the BAUD from the UART_CLK. - * - * BAUD = UART_CLK / (16 * DL), or - * DIV = UART_CLK / BAUD / 16 - * - * Ignoring the fractional divider for now. - * - ************************************************************************************/ - -#ifndef CONFIG_16550_SUPRESS_CONFIG -static inline uint32_t u16550_divisor(struct u16550_s *priv) -{ - return (priv->uartclk + (priv->baud << 3)) / (priv->baud << 4); -} -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: u16550_setup - * - * Description: - * Configure the UART baud, bits, parity, fifos, etc. This - * method is called the first time that the serial port is - * opened. - * - ****************************************************************************/ - -static int u16550_setup(struct uart_dev_s *dev) -{ -#ifndef CONFIG_16550_SUPRESS_CONFIG - struct u16550_s *priv = (struct u16550_s*)dev->priv; - uint16_t div; - uint32_t lcr; - - /* Clear fifos */ - - u16550_serialout(priv, UART_FCR_OFFSET, (UART_FCR_RXRST|UART_FCR_TXRST)); - - /* Set trigger */ - - u16550_serialout(priv, UART_FCR_OFFSET, (UART_FCR_FIFOEN|UART_FCR_RXTRIGGER_8)); - - /* Set up the IER */ - -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - priv->ier = u16550_serialin(priv, UART_IER_OFFSET); -#endif - - /* Set up the LCR */ - - lcr = 0; - switch (priv->bits) - { - case 5 : - lcr |= UART_LCR_WLS_7BIT; - break; - - case 6 : - lcr |= UART_LCR_WLS_7BIT; - break; - - case 7 : - lcr |= UART_LCR_WLS_7BIT; - break; - - default: - case 8 : - lcr |= UART_LCR_WLS_7BIT; - break; - } - - if (priv->stopbits2) - { - lcr |= UART_LCR_STB; - } - - if (priv->parity == 1) - { - lcr |= UART_LCR_PEN; - } - else if (priv->parity == 2) - { - lcr |= (UART_LCR_PEN|UART_LCR_EPS); - } - - /* Enter DLAB=1 */ - - u16550_serialout(priv, UART_LCR_OFFSET, (lcr | UART_LCR_DLAB)); - - /* Set the BAUD divisor */ - - div = u16550_divisor(priv); - u16550_serialout(priv, UART_DLM_OFFSET, div >> 8); - u16550_serialout(priv, UART_DLL_OFFSET, div & 0xff); - - /* Clear DLAB */ - - u16550_serialout(priv, UART_LCR_OFFSET, lcr); - - /* Configure the FIFOs */ - - u16550_serialout(priv, UART_FCR_OFFSET, - (UART_FCR_RXTRIGGER_8|UART_FCR_TXRST|UART_FCR_RXRST|UART_FCR_FIFOEN)); -#endif - return OK; -} - -/**************************************************************************** - * Name: u16550_shutdown - * - * Description: - * Disable the UART. This method is called when the serial - * port is closed - * - ****************************************************************************/ - -static void u16550_shutdown(struct uart_dev_s *dev) -{ - struct u16550_s *priv = (struct u16550_s*)dev->priv; - u16550_disableuartint(priv, NULL); -} - -/**************************************************************************** - * Name: u16550_attach - * - * Description: - * Configure the UART to operation in interrupt driven mode. This method is - * called when the serial port is opened. Normally, this is just after the - * the setup() method is called, however, the serial console may operate in - * a non-interrupt driven mode during the boot phase. - * - * RX and TX interrupts are not enabled when by the attach method (unless the - * hardware supports multiple levels of interrupt enabling). The RX and TX - * interrupts are not enabled until the txint() and rxint() methods are called. - * - ****************************************************************************/ - -static int u16550_attach(struct uart_dev_s *dev) -{ -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - struct u16550_s *priv = (struct u16550_s*)dev->priv; - int ret; - - /* Attach and enable the IRQ */ - - ret = irq_attach(priv->irq, u16550_interrupt); -#ifndef CONFIG_ARCH_NOINTC - if (ret == OK) - { - /* Enable the interrupt (RX and TX interrupts are still disabled - * in the UART - */ - - up_enable_irq(priv->irq); - } -#endif - return ret; -#else - return OK; -#endif -} - -/**************************************************************************** - * Name: u16550_detach - * - * Description: - * Detach UART interrupts. This method is called when the serial port is - * closed normally just before the shutdown method is called. The exception is - * the serial console which is never shutdown. - * - ****************************************************************************/ - -static void u16550_detach(struct uart_dev_s *dev) -{ -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - struct u16550_s *priv = (struct u16550_s*)dev->priv; -#ifndef CONFIG_ARCH_NOINTC - up_disable_irq(priv->irq); -#endif - irq_detach(priv->irq); -#endif -} - -/**************************************************************************** - * Name: u16550_interrupt - * - * Description: - * This is the UART interrupt handler. It will be invoked when an - * interrupt received on the 'irq' It should call uart_transmitchars or - * uart_receivechar to perform the appropriate data transfers. The - * interrupt handling logic must be able to map the 'irq' number into the - * appropriate u16550_s structure in order to call these functions. - * - ****************************************************************************/ - -#ifndef CONFIG_SUPPRESS_SERIAL_INTS -static int u16550_interrupt(int irq, void *context) -{ - struct uart_dev_s *dev = NULL; - struct u16550_s *priv; - uint32_t status; - int passes; - -#ifdef CONFIG_16550_UART0 - if (g_uart0priv.irq == irq) - { - dev = &g_uart0port; - } - else -#endif -#ifdef CONFIG_16550_UART1 - if (g_uart1priv.irq == irq) - { - dev = &g_uart1port; - } - else -#endif -#ifdef CONFIG_16550_UART2 - if (g_uart2priv.irq == irq) - { - dev = &g_uart2port; - } - else -#endif -#ifdef CONFIG_16550_UART3 - if (g_uart3priv.irq == irq) - { - dev = &g_uart3port; - } -#endif - ASSERT(dev != NULL); - priv = (struct u16550_s*)dev->priv; - - /* Loop until there are no characters to be transferred or, - * until we have been looping for a long time. - */ - - for (passes = 0; passes < 256; passes++) - { - /* Get the current UART status and check for loop - * termination conditions - */ - - status = u16550_serialin(priv, UART_IIR_OFFSET); - - /* The UART_IIR_INTSTATUS bit should be zero if there are pending - * interrupts - */ - - if ((status & UART_IIR_INTSTATUS) != 0) - { - /* Break out of the loop when there is no longer a - * pending interrupt - */ - - break; - } - - /* Handle the interrupt by its interrupt ID field */ - - switch (status & UART_IIR_INTID_MASK) - { - /* Handle incoming, receive bytes (with or without timeout) */ - - case UART_IIR_INTID_RDA: - case UART_IIR_INTID_CTI: - { - uart_recvchars(dev); - break; - } - - /* Handle outgoing, transmit bytes */ - - case UART_IIR_INTID_THRE: - { - uart_xmitchars(dev); - break; - } - - /* Just clear modem status interrupts (UART1 only) */ - - case UART_IIR_INTID_MSI: - { - /* Read the modem status register (MSR) to clear */ - - status = u16550_serialin(priv, UART_MSR_OFFSET); - vdbg("MSR: %02x\n", status); - break; - } - - /* Just clear any line status interrupts */ - - case UART_IIR_INTID_RLS: - { - /* Read the line status register (LSR) to clear */ - - status = u16550_serialin(priv, UART_LSR_OFFSET); - vdbg("LSR: %02x\n", status); - break; - } - - /* There should be no other values */ - - default: - { - dbg("Unexpected IIR: %02x\n", status); - break; - } - } - } - - return OK; -} -#endif - -/**************************************************************************** - * Name: u16550_ioctl - * - * Description: - * All ioctl calls will be routed through this method - * - ****************************************************************************/ - -static int u16550_ioctl(struct file *filep, int cmd, unsigned long arg) -{ - struct inode *inode = filep->f_inode; - struct uart_dev_s *dev = inode->i_private; - struct u16550_s *priv = (struct u16550_s*)dev->priv; - int ret = OK; - - switch (cmd) - { - case TIOCSERGSTRUCT: - { - struct u16550_s *user = (struct u16550_s*)arg; - if (!user) - { - set_errno(EINVAL); - ret = ERROR; - } - else - { - memcpy(user, dev, sizeof(struct u16550_s)); - } - } - break; - - case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ - { - irqstate_t flags = irqsave(); - u16550_enablebreaks(priv, true); - irqrestore(flags); - } - break; - - case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ - { - irqstate_t flags; - flags = irqsave(); - u16550_enablebreaks(priv, false); - irqrestore(flags); - } - break; - - default: - set_errno(ENOTTY); - ret = ERROR; - break; - } - - return ret; -} - -/**************************************************************************** - * Name: u16550_receive - * - * Description: - * Called (usually) from the interrupt level to receive one - * character from the UART. Error bits associated with the - * receipt are provided in the return 'status'. - * - ****************************************************************************/ - -static int u16550_receive(struct uart_dev_s *dev, uint32_t *status) -{ - struct u16550_s *priv = (struct u16550_s*)dev->priv; - uint32_t rbr; - - *status = u16550_serialin(priv, UART_LSR_OFFSET); - rbr = u16550_serialin(priv, UART_RBR_OFFSET); - return rbr; -} - -/**************************************************************************** - * Name: u16550_rxint - * - * Description: - * Call to enable or disable RX interrupts - * - ****************************************************************************/ - -static void u16550_rxint(struct uart_dev_s *dev, bool enable) -{ -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - struct u16550_s *priv = (struct u16550_s*)dev->priv; - if (enable) - { - priv->ier |= UART_IER_ERBFI; - } - else - { - priv->ier &= ~UART_IER_ERBFI; - } - u16550_serialout(priv, UART_IER_OFFSET, priv->ier); -#endif -} - -/**************************************************************************** - * Name: u16550_rxavailable - * - * Description: - * Return true if the receive fifo is not empty - * - ****************************************************************************/ - -static bool u16550_rxavailable(struct uart_dev_s *dev) -{ - struct u16550_s *priv = (struct u16550_s*)dev->priv; - return ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_DR) != 0); -} - -/**************************************************************************** - * Name: u16550_send - * - * Description: - * This method will send one byte on the UART - * - ****************************************************************************/ - -static void u16550_send(struct uart_dev_s *dev, int ch) -{ - struct u16550_s *priv = (struct u16550_s*)dev->priv; - u16550_serialout(priv, UART_THR_OFFSET, (uart_datawidth_t)ch); -} - -/**************************************************************************** - * Name: u16550_txint - * - * Description: - * Call to enable or disable TX interrupts - * - ****************************************************************************/ - -static void u16550_txint(struct uart_dev_s *dev, bool enable) -{ -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - struct u16550_s *priv = (struct u16550_s*)dev->priv; - irqstate_t flags; - - flags = irqsave(); - if (enable) - { - priv->ier |= UART_IER_ETBEI; - u16550_serialout(priv, UART_IER_OFFSET, priv->ier); - - /* Fake a TX interrupt here by just calling uart_xmitchars() with - * interrupts disabled (note this may recurse). - */ - - uart_xmitchars(dev); - } - else - { - priv->ier &= ~UART_IER_ETBEI; - u16550_serialout(priv, UART_IER_OFFSET, priv->ier); - } - - irqrestore(flags); -#endif -} - -/**************************************************************************** - * Name: u16550_txready - * - * Description: - * Return true if the tranmsit fifo is not full - * - ****************************************************************************/ - -static bool u16550_txready(struct uart_dev_s *dev) -{ - struct u16550_s *priv = (struct u16550_s*)dev->priv; - return ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) != 0); -} - -/**************************************************************************** - * Name: u16550_txempty - * - * Description: - * Return true if the transmit fifo is empty - * - ****************************************************************************/ - -static bool u16550_txempty(struct uart_dev_s *dev) -{ - struct u16550_s *priv = (struct u16550_s*)dev->priv; - return ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) != 0); -} - -/**************************************************************************** - * Name: u16550_putc - * - * Description: - * Write one character to the UART (polled) - * - ****************************************************************************/ - -static void u16550_putc(struct u16550_s *priv, int ch) -{ - while ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) != 0); - u16550_serialout(priv, UART_THR_OFFSET, (uart_datawidth_t)ch); -} - -/**************************************************************************** - * Public Funtions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_earlyserialinit - * - * Description: - * Performs the low level UART initialization early in debug so that the - * serial console will be available during bootup. This must be called - * before uart_serialinit. - * - * NOTE: Configuration of the CONSOLE UART was performed by uart_lowsetup() - * very early in the boot sequence. - * - ****************************************************************************/ - -void up_earlyserialinit(void) -{ - /* Configure all UARTs (except the CONSOLE UART) and disable interrupts */ - -#ifdef CONFIG_16550_UART0 - u16550_disableuartint(&g_uart0priv, NULL); -#endif -#ifdef CONFIG_16550_UART1 - u16550_disableuartint(&g_uart1priv, NULL); -#endif -#ifdef CONFIG_16550_UART2 - u16550_disableuartint(&g_uart2priv, NULL); -#endif -#ifdef CONFIG_16550_UART3 - u16550_disableuartint(&g_uart3priv, NULL); -#endif - - /* Configuration whichever one is the console */ - -#ifdef CONSOLE_DEV - CONSOLE_DEV.isconsole = true; - u16550_setup(&CONSOLE_DEV); -#endif -} - -/**************************************************************************** - * Name: up_serialinit - * - * Description: - * Register serial console and serial ports. This assumes that - * up_earlyserialinit was called previously. - * - ****************************************************************************/ - -void up_serialinit(void) -{ -#ifdef CONSOLE_DEV - (void)uart_register("/dev/console", &CONSOLE_DEV); -#endif -#ifdef TTYS0_DEV - (void)uart_register("/dev/ttyS0", &TTYS0_DEV); -#endif -#ifdef TTYS1_DEV - (void)uart_register("/dev/ttyS1", &TTYS1_DEV); -#endif -#ifdef TTYS2_DEV - (void)uart_register("/dev/ttyS2", &TTYS2_DEV); -#endif -#ifdef TTYS3_DEV - (void)uart_register("/dev/ttyS3", &TTYS3_DEV); -#endif -} - -/**************************************************************************** - * Name: up_putc - * - * Description: - * Provide priority, low-level access to support OS debug writes - * - ****************************************************************************/ - -#ifdef HAVE_16550_CONSOLE -int up_putc(int ch) -{ - struct u16550_s *priv = (struct u16550_s*)CONSOLE_DEV.priv; -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - uart_datawidth_t ier; - - u16550_disableuartint(priv, &ier); -#endif - - /* Check for LF */ - - if (ch == '\n') - { - /* Add CR */ - - u16550_putc(priv, '\r'); - } - - u16550_putc(priv, ch); -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - u16550_restoreuartint(priv, ier); -#endif - return ch; -} -#endif - -#endif /* CONFIG_16550_UART */ diff --git a/nuttx/drivers/syslog/Kconfig b/nuttx/drivers/syslog/Kconfig deleted file mode 100644 index 3ec8c7490..000000000 --- a/nuttx/drivers/syslog/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -comment "System Logging" - -config RAMLOG - bool "RAM log device support" - default n - ---help--- - This is a driver that was intended to support debugging output, - aka syslogging, when the normal serial output is not available. - For example, if you are using a telnet or USB serial console, - the debug output will get lost. However, the RAMLOG device should - be usable even if system logging is disabled. - - This driver is similar to a pipe in that it saves the debugging - output in a FIFO in RAM. It differs from a pipe in numerous - details as needed to support logging. - -if RAMLOG -config RAMLOG_SYSLOG - bool "Use RAMLOG for SYSLOG" - default n - depends on SYSLOG - ---help--- - Use the RAM logging device for the syslogging interface. If this feature - is enabled (along with SYSLOG), then all debug output (only) will be re-directed - to the circular buffer in RAM. This RAM log can be view from NSH using the - 'dmesg'command. - - Do not enable more than one SYSLOG device. - -config RAMLOG_CONSOLE - bool "Use RAMLOG for /dev/console" - default n - depends on DEV_CONSOLE - ---help--- - Use the RAM logging device as a system console. If this feature is enabled (along - with DEV_CONSOLE), then all console output will be re-directed to a circular - buffer in RAM. This is useful, for example, if the only console is a Telnet - console. Then in that case, console output from non-Telnet threads will go to - the circular buffer and can be viewed using the NSH 'dmesg' command. - -config RAMLOG_CONSOLE_BUFSIZE - int "RAMLOG buffer size" - default 1024 - depends on RAMLOG_SYSLOG || RAMLOG_CONSOLE - ---help--- - Size of the console RAM log. Default: 1024 - -config RAMLOG_CRLF - bool "RAMLOG CR/LF" - default n - ---help--- - Pre-pend a carriage return before every linefeed that goes into the RAM log. - -config RAMLOG_NONBLOCKING - bool "RAMLOG non-block reads" - default y - ---help--- - Reading from the RAMLOG will never block if the RAMLOG is empty. If the RAMLOG - is empty, then zero is returned (usually interpreted as end-of-file). - -config RAMLOG_NPOLLWAITERS - int "RAMLOG number of poll waiters" - default 4 - depends on !DISABLE_POLL - ---help--- - The maximum number of threads that may be waiting on the poll method. - -endif diff --git a/nuttx/drivers/syslog/Make.defs b/nuttx/drivers/syslog/Make.defs deleted file mode 100644 index aa0ab19b8..000000000 --- a/nuttx/drivers/syslog/Make.defs +++ /dev/null @@ -1,68 +0,0 @@ -############################################################################ -# drivers/syslog/Make.defs -# These drivers support system logging devices -# -# Copyright (C) 2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Include SYSLOG drivers (only one should be enabled) - -ifeq ($(CONFIG_SYSLOG),y) - -# If no special loggin devices are implemented, then the default SYSLOG -# logic at fs/fs_syslog.c will be used - -# (Add other SYSLOG drivers here) - -ifeq ($(CONFIG_RAMLOG),y) - CSRCS += ramlog.c -endif - -# Include SYSLOG build support - -DEPPATH += --dep-path syslog -VPATH += :syslog - -else - -# The RAMLOG can be used even if system logging is not enabled. - -ifeq ($(CONFIG_RAMLOG),y) - -# Include RAMLOG build support - -CSRCS += ramlog.c -DEPPATH += --dep-path syslog -VPATH += :syslog - -endif -endif diff --git a/nuttx/drivers/syslog/README.txt b/nuttx/drivers/syslog/README.txt deleted file mode 100644 index bfef73ae8..000000000 --- a/nuttx/drivers/syslog/README.txt +++ /dev/null @@ -1,64 +0,0 @@ -drivers/syslog README File -========================== - -This README file discusses the SYLOG drivers that can be found in the -drivers/syslog directory. In NuttX, syslog output is equivalent to -debug output and, therefore, the syslogging interfaces are defined in the -header file include/debug.h. - -By default, all system log output goes to console (/dev/console). But that -behavior can be changed by the defining CONFIG_SYSLOG in the NuttX -configuration. In that, case all low-level debug output will go through -syslog_putc(). - -One version of syslog_putc() is defined in fs/fs_syslog.c; that version is -used when CONFIG_SYSLOG_CHAR is defined. That version of syslog_putc() -just integrates with the file system to re-direct debug output to a -character device or to a file. A disadvantage of using the generic character -device for the SYSLOG is that it cannot handle debug output generated from -interrupt level handles. - -If CONFIG_SYSLOG_CHAR is not defined, then other custom SYSLOG drivers -can be used. These custom SYSLOG drivers can do things like handle -unusual logging media and since they can avoid the general file system -interfaces, can be designed to support debug output from interrupt handlers. - -Those custom SYSLOG drivers reside in this directory. - -ramlog.c --------- - The RAM logging driver is a driver that was intended to support debugging - output (syslogging) when the normal serial output is not available. For - example, if you are using a telnet or USB serial console, the debug - output will get lost. - - The RAM logging driver is similar to a pipe in that it saves the - debugging output in a FIFO in RAM. It differs from a pipe in numerous - details as needed to support logging. - - This driver is built when CONFIG_RAMLOG is defined in the Nuttx - configuration. - - Configuration options: - - CONFIG_RAMLOG - Enables the RAM logging feature - CONFIG_RAMLOG_CONSOLE - Use the RAM logging device as a system console. - If this feature is enabled (along with CONFIG_DEV_CONSOLE), then all - console output will be re-directed to a circular buffer in RAM. This - is useful, for example, if the only console is a Telnet console. Then - in that case, console output from non-Telnet threads will go to the - circular buffer and can be viewed using the NSH 'dmesg' command. - CONFIG_RAMLOG_SYSLOG - Use the RAM logging device for the syslogging - interface. If this feature is enabled (along with CONFIG_SYSLOG), - then all debug output (only) will be re-directed to the circular - buffer in RAM. This RAM log can be view from NSH using the 'dmesg' - command. NOTE: Unlike the limited, generic character driver SYSLOG - device, the RAMLOG *can* be used to generate debug output from interrupt - level handlers. - CONFIG_RAMLOG_NPOLLWAITERS - The number of threads than can be waiting - for this driver on poll(). Default: 4 - - If CONFIG_RAMLOG_CONSOLE or CONFIG_RAMLOG_SYSLOG is selected, then the - following may also be provided: - - CONFIG_RAMLOG_CONSOLE_BUFSIZE - Size of the console RAM log. Default: 1024 diff --git a/nuttx/drivers/syslog/ramlog.c b/nuttx/drivers/syslog/ramlog.c deleted file mode 100644 index 08bbbfb59..000000000 --- a/nuttx/drivers/syslog/ramlog.c +++ /dev/null @@ -1,770 +0,0 @@ -/**************************************************************************** - * drivers/syslog/ramlog.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_RAMLOG - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct ramlog_dev_s -{ -#ifndef CONFIG_RAMLOG_NONBLOCKING - volatile uint8_t rl_nwaiters; /* Number of threads waiting for data */ -#endif - volatile uint16_t rl_head; /* The head index (where data is added) */ - volatile uint16_t rl_tail; /* The tail index (where data is removed) */ - sem_t rl_exclsem; /* Enforces mutually exclusive access */ -#ifndef CONFIG_RAMLOG_NONBLOCKING - sem_t rl_waitsem; /* Used to wait for data */ -#endif - size_t rl_bufsize; /* Size of the RAM buffer */ - FAR char *rl_buffer; /* Circular RAM buffer */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *rl_fds[CONFIG_RAMLOG_NPOLLWAITERS]; -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* Helper functions */ - -#ifndef CONFIG_DISABLE_POLL -static void ramlog_pollnotify(FAR struct ramlog_dev_s *priv, - pollevent_t eventset); -#endif -static ssize_t ramlog_addchar(FAR struct ramlog_dev_s *priv, char ch); - -/* Character driver methods */ - -static ssize_t ramlog_read(FAR struct file *, FAR char *, size_t); -static ssize_t ramlog_write(FAR struct file *, FAR const char *, size_t); -#ifndef CONFIG_DISABLE_POLL -static int ramlog_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations g_ramlogfops = -{ - 0, /* open */ - 0, /* close */ - ramlog_read, /* read */ - ramlog_write, /* write */ - 0, /* seek */ - 0 /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , ramlog_poll /* poll */ -#endif -}; - -/* This is the pre-allocated buffer used for the console RAM log and/or - * for the syslogging function. - */ - -#if defined(CONFIG_RAMLOG_CONSOLE) || defined(CONFIG_RAMLOG_SYSLOG) -static char g_sysbuffer[CONFIG_RAMLOG_CONSOLE_BUFSIZE]; - -/* This is the device structure for the console or syslogging function. It - * must be statically initialized because the RAMLOG syslog_putc function - * could be called before the driver initialization logic executes. - */ - -static struct ramlog_dev_s g_sysdev = -{ -#ifndef CONFIG_RAMLOG_NONBLOCKING - 0, /* rl_nwaiters */ -#endif - 0, /* rl_head */ - 0, /* rl_tail */ - SEM_INITIALIZER(1), /* rl_exclsem */ -#ifndef CONFIG_RAMLOG_NONBLOCKING - SEM_INITIALIZER(0), /* rl_waitsem */ -#endif - CONFIG_RAMLOG_CONSOLE_BUFSIZE, /* rl_bufsize */ - g_sysbuffer /* rl_buffer */ -}; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ramlog_pollnotify - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static void ramlog_pollnotify(FAR struct ramlog_dev_s *priv, - pollevent_t eventset) -{ - FAR struct pollfd *fds; - irqstate_t flags; - int i; - - /* This function may be called from an interrupt handler */ - - for (i = 0; i < CONFIG_RAMLOG_NPOLLWAITERS; i++) - { - flags = irqsave(); - fds = priv->rl_fds[i]; - if (fds) - { - fds->revents |= (fds->events & eventset); - if (fds->revents != 0) - { - sem_post(fds->sem); - } - } - irqrestore(flags); - } -} -#else -# define ramlog_pollnotify(priv,event) -#endif - -/**************************************************************************** - * Name: ramlog_addchar - ****************************************************************************/ - -static int ramlog_addchar(FAR struct ramlog_dev_s *priv, char ch) -{ - irqstate_t flags; - int nexthead; - - /* Disable interrupts (in case we are NOT called from interrupt handler) */ - - flags = irqsave(); - - /* Calculate the write index AFTER the next byte is written */ - - nexthead = priv->rl_head + 1; - if (nexthead >= priv->rl_bufsize) - { - nexthead = 0; - } - - /* Would the next write overflow the circular buffer? */ - - if (nexthead == priv->rl_tail) - { - /* Yes... Return an indication that nothing was saved in the buffer. */ - - irqrestore(flags); - return -EBUSY; - } - - /* No... copy the byte and re-enable interrupts */ - - priv->rl_buffer[priv->rl_head] = ch; - priv->rl_head = nexthead; - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Name: ramlog_read - ****************************************************************************/ - -static ssize_t ramlog_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - struct inode *inode = filep->f_inode; - struct ramlog_dev_s *priv; - ssize_t nread; - char ch; - int ret; - - /* Some sanity checking */ - - DEBUGASSERT(inode && inode->i_private); - priv = inode->i_private; - - /* If the circular buffer is empty, then wait for something to be written - * to it. This function may NOT be called from an interrupt handler. - */ - - DEBUGASSERT(!up_interrupt_context()); - - /* Get exclusive access to the rl_tail index */ - - ret = sem_wait(&priv->rl_exclsem); - if (ret < 0) - { - return ret; - } - - /* Loop until something is read */ - - for (nread = 0; nread < len; ) - { - /* Get the next byte from the buffer */ - - if (priv->rl_head == priv->rl_tail) - { - /* The circular buffer is empty. */ - -#ifdef CONFIG_RAMLOG_NONBLOCKING - /* Return what we have (with zero mean the end-of-file) */ - - break; -#else - /* Did we read anything? */ - - if (nread > 0) - { - /* Yes.. re-enable interrupts and the break out to return what - * we have. - */ - - break; - } - - /* If the driver was opened with O_NONBLOCK option, then don't wait. - * Re-enable interrupts and return EGAIN. - */ - - if (filep->f_oflags & O_NONBLOCK) - { - nread = -EAGAIN; - break; - } - - /* Otherwise, wait for something to be written to the circular - * buffer. Increment the number of waiters so that the ramlog_write() - * will not that it needs to post the semaphore to wake us up. - */ - - sched_lock(); - priv->rl_nwaiters++; - sem_post(&priv->rl_exclsem); - - /* We may now be pre-empted! But that should be okay because we - * have already incremented nwaiters. Pre-emptions is disabled - * but will be re-enabled while we are waiting. - */ - - ret = sem_wait(&priv->rl_waitsem); - - /* Interrupts will be disabled when we return. So the decrementing - * rl_nwaiters here is safe. - */ - - priv->rl_nwaiters--; - sched_unlock(); - - /* Did we successfully get the rl_waitsem? */ - - if (ret >= 0) - { - /* Yes... then retake the mutual exclusion semaphore */ - - ret = sem_wait(&priv->rl_exclsem); - } - - /* Was the semaphore wait successful? Did we successful re-take the - * mutual exclusion semaphore? - */ - - if (ret < 0) - { - /* No.. One of the two sem_wait's failed. */ - - int errval = errno; - - /* Were we awakened by a signal? Did we read anything before - * we received the signal? - */ - - if (errval != EINTR || nread >= 0) - { - /* Yes.. return the error. */ - - nread = -errval; - } - - /* Break out to return what we have. Note, we can't exactly - * "break" out because whichever error occurred, we do not hold - * the exclusion semaphore. - */ - - goto errout_without_sem; - } -#endif /* CONFIG_RAMLOG_NONBLOCKING */ - } - else - { - /* The circular buffer is not empty, get the next byte from the - * tail index. - */ - - ch = priv->rl_buffer[priv->rl_tail]; - - /* Increment the tail index and re-enable interrupts */ - - if (++priv->rl_tail >= priv->rl_bufsize) - { - priv->rl_tail = 0; - } - - /* Add the character to the user buffer */ - - buffer[nread] = ch; - nread++; - } - } - - /* Relinquish the mutual exclusion semaphore */ - - sem_post(&priv->rl_exclsem); - - /* Notify all poll/select waiters that they can write to the FIFO */ - -#ifndef CONFIG_RAMLOG_NONBLOCKING -errout_without_sem: -#endif - -#ifndef CONFIG_DISABLE_POLL - if (nread > 0) - { - ramlog_pollnotify(priv, POLLOUT); - } -#endif - - /* Return the number of characters actually read */ - - return nread; -} - -/**************************************************************************** - * Name: ramlog_write - ****************************************************************************/ - -static ssize_t ramlog_write(FAR struct file *filep, FAR const char *buffer, size_t len) -{ - struct inode *inode = filep->f_inode; - struct ramlog_dev_s *priv; - ssize_t nwritten; - char ch; - int ret; - - /* Some sanity checking */ - - DEBUGASSERT(inode && inode->i_private); - priv = inode->i_private; - - /* Loop until all of the bytes have been written. This function may be - * called from an interrupt handler! Semaphores cannot be used! - * - * The write logic only needs to modify the rl_head index. Therefore, - * there is a difference in the way that rl_head and rl_tail are protected: - * rl_tail is protected with a semaphore; rl_tail is protected by disabling - * interrupts. - */ - - for (nwritten = 0; nwritten < len; nwritten++) - { - /* Get the next character to output */ - - ch = buffer[nwritten]; - - /* Ignore carriage returns */ - -#ifdef CONFIG_RAMLOG_CRLF - if (ch == '\r') - { - continue; - } - - /* Pre-pend a carriage before a linefeed */ - - if (ch == '\n') - { - ret = ramlog_addchar(priv, '\r'); - if (ret < 0) - { - /* The buffer is full and nothing was saved. Break out of the - * loop to return the number of bytes written up to this point. - * The data to be written is dropped on the floor. - */ - - break; - } - } -#endif - - /* Then output the character */ - - ret = ramlog_addchar(priv,ch); - if (ret < 0) - { - /* The buffer is full and nothing was saved. Break out of the - * loop to return the number of bytes written up to this point. - * The data to be written is dropped on the floor. - */ - - break; - } - } - - /* Was anything written? */ - -#if !defined(CONFIG_RAMLOG_NONBLOCKING) || !defined(CONFIG_DISABLE_POLL) - if (nwritten > 0) - { - irqstate_t flags; -#ifndef CONFIG_RAMLOG_NONBLOCKING - int i; -#endif - - /* Are there threads waiting for read data? */ - - flags = irqsave(); -#ifndef CONFIG_RAMLOG_NONBLOCKING - for (i = 0; i < priv->rl_nwaiters; i++) - { - /* Yes.. Notify all of the waiting readers that more data is available */ - - sem_post(&priv->rl_waitsem); - } -#endif - - /* Notify all poll/select waiters that they can write to the FIFO */ - - ramlog_pollnotify(priv, POLLIN); - irqrestore(flags); - } -#endif - - /* We always have to return the number of bytes requested and NOT the - * number of bytes that were actually written. Otherwise, callers - * will think that this is a short write and probably retry (causing - */ - - return len; -} - -/**************************************************************************** - * Name: ramlog_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -int ramlog_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct ramlog_dev_s *priv; - pollevent_t eventset; - int ndx; - int ret; - int i; - - /* Some sanity checking */ - - DEBUGASSERT(inode && inode->i_private); - priv = inode->i_private; - - /* Get exclusive access to the poll structures */ - - ret = sem_wait(&priv->rl_exclsem); - if (ret < 0) - { - int errval = errno; - return -errval; - } - - /* Are we setting up the poll? Or tearing it down? */ - - if (setup) - { - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_RAMLOG_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->rl_fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->rl_fds[i] = fds; - fds->priv = &priv->rl_fds[i]; - break; - } - } - - if (i >= CONFIG_RAMLOG_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should immediately notify on any of the requested events? - * First, check if the xmit buffer is full. - */ - - eventset = 0; - - ndx = priv->rl_head + 1; - if (ndx >= priv->rl_bufsize) - { - ndx = 0; - } - - if (ndx != priv->rl_tail) - { - eventset |= POLLOUT; - } - - /* Check if the receive buffer is empty */ - - if (priv->rl_head != priv->rl_tail) - { - eventset |= POLLIN; - } - - if (eventset) - { - ramlog_pollnotify(priv, eventset); - } - - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - -#ifdef CONFIG_DEBUG - if (!slot) - { - ret = -EIO; - goto errout; - } -#endif - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->rl_exclsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ramlog_register - * - * Description: - * Create the RAM logging device and register it at the specified path. - * Mostly likely this path will be /dev/console - * - ****************************************************************************/ - -#if !defined(CONFIG_RAMLOG_CONSOLE) && !defined(CONFIG_RAMLOG_SYSLOG) -int ramlog_register(FAR const char *devpath, FAR char *buffer, size_t buflen) -{ - FAR struct ramlog_dev_s *priv; - int ret = -ENOMEM; - - /* Sanity checking */ - - DEBUGASSERT(devpath && buffer && buflen > 1); - - /* Allocate a RAM logging device structure */ - - priv = (struct ramlog_dev_s *)kzalloc(sizeof(struct ramlog_dev_s)); - if (priv) - { - /* Initialize the non-zero values in the RAM logging device structure */ - - sem_init(&priv->rl_exclsem, 0, 1); -#ifndef CONFIG_RAMLOG_NONBLOCKING - sem_init(&priv->rl_waitsem, 0, 0); -#endif - priv->rl_bufsize = buflen; - priv->rl_buffer = buffer; - - /* Register the character driver */ - - ret = register_driver(devpath, &g_ramlogfops, 0666, priv); - if (ret < 0) - { - kfree(priv); - } - } - - return ret; -} -#endif - -/**************************************************************************** - * Name: ramlog_consoleinit - * - * Description: - * Create the RAM logging device and register it at the specified path. - * Mostly likely this path will be /dev/console - * - ****************************************************************************/ - -#ifdef CONFIG_RAMLOG_CONSOLE -int ramlog_consoleinit(void) -{ - FAR struct ramlog_dev_s *priv = &g_sysdev; - int ret; - - /* Register the console character driver */ - - ret = register_driver("/dev/console", &g_ramlogfops, 0666, priv); -} -#endif - -/**************************************************************************** - * Name: ramlog_sysloginit - * - * Description: - * Create the RAM logging device and register it at the specified path. - * Mostly likely this path will be CONFIG_RAMLOG_SYSLOG - * - * If CONFIG_RAMLOG_CONSOLE is also defined, then this functionality is - * performed when ramlog_consoleinit() is called. - * - ****************************************************************************/ - -#ifdef CONFIG_RAMLOG_SYSLOG -int ramlog_sysloginit(void) -{ - /* Register the syslog character driver */ - - return register_driver(CONFIG_SYSLOG_DEVPATH, &g_ramlogfops, 0666, &g_sysdev); -} -#endif - -/**************************************************************************** - * Name: syslog_putc - * - * Description: - * This is the low-level system logging interface. The debugging/syslogging - * interfaces are syslog() and lowsyslog(). The difference is that - * the syslog() internface writes to fd=1 (stdout) whereas lowsyslog() uses - * a lower level interface that works from interrupt handlers. This - * function is a a low-level interface used to implement lowsyslog() - * when CONFIG_RAMLOG_SYSLOG=y and CONFIG_SYSLOG=y - * - ****************************************************************************/ - -#if defined(CONFIG_RAMLOG_CONSOLE) || defined(CONFIG_RAMLOG_SYSLOG) -int syslog_putc(int ch) -{ - FAR struct ramlog_dev_s *priv = &g_sysdev; - int ret; - - /* Ignore carriage returns */ - -#ifdef CONFIG_RAMLOG_CRLF - if (ch == '\r') - { - return ch; - } - - /* Pre-pend a newline with a carriage return */ - - if (ch == '\n') - { - ret = ramlog_addchar(priv, '\r'); - if (ret < 0) - { - /* The buffer is full and nothing was saved. */ - - return ch; - } - } -#endif - - (void)ramlog_addchar(priv, ch); - return ch; -} -#endif - -#endif /* CONFIG_RAMLOG */ diff --git a/nuttx/drivers/usbdev/Kconfig b/nuttx/drivers/usbdev/Kconfig deleted file mode 100644 index 0752bb791..000000000 --- a/nuttx/drivers/usbdev/Kconfig +++ /dev/null @@ -1,513 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -menu "Device Controller Driver Options" - -config USBDEV_ISOCHRONOUS - bool "Enable isochronous" - default n - ---help--- - Build in extra support for isochronous endpoints - -config USBDEV_DUALSPEED - bool "Enable high and full speed" - default n - ---help--- - Hardware handles high and full speed operation (USB 2.0) - -choice USBDEV_POWERED - prompt "Select USB device powered" - default USBDEV_SELFPOWERED - -config USBDEV_SELFPOWERED - bool "Self powered" - ---help--- - Will cause USB features to indicate that the device is self-powered - -config USBDEV_BUSPOWERED - bool "Bus powered" - ---help--- - Will cause USB features to indicate that the device is self-powered - -endchoice - -config USBDEV_MAXPOWER - int "Maximum power consumption in mA" - default 100 - depends on USBDEV_BUSPOWERED - ---help--- - Maximum power consumption in mA - -config USBDEV_DMA - bool "Enable DMA methods" - default n - ---help--- - Select this enable DMA-related methods in USB device controller driver - interface. These methods include the DMA buffer allocation methods: - allobuffer() and freebuffer(). - - The USB class driver allocates packet I/O buffers for data transfer by - calling the driver allocbuffer() and freebuffer() methods. Those methods - are only available if USBDEV_DMA is defined in the system configuration. - -config USBDEV_DMAMEMORY -bool "Board DMA Allocation Hooks" - default n - depends on USBDEV_DMA - ---help--- - The USB class driver allocates packet I/O buffers for data transfer by - calling the driver allocbuffer() and freebuffer() methods. Those methods - are only available if USBDEV_DMA is defined in the system configuration. - - If USBDEV_DMAMEMORY is also defined in the NuttX configuration, then - the driver implementations of the allocbuffer() and freebuffer() - methods may use board-specific usbdev_dma_alloc() and usbdev_dma_free(). - If USBDEV_DMA and USBDEV_DMAMEMORY are both defined, then the board- - specific logic must provide the functions usbdev_dma_alloc() and - usbdev_dma_free(): usbdev_dma_alloc() will allocate DMA-capable - memory of the specified size; usbdev_dma_free() is the corresponding - function that will be called to free the DMA-capable memory. - -config USBDEV_TRACE - bool "Enable USB tracing for debug" - default n - ---help--- - Enables USB tracing for debug - -config USBDEV_TRACE_NRECORDS - int "Number of trace entries to remember" - default 32 - depends on USBDEV_TRACE - ---help--- - Number of trace entries to remember - -endmenu - -menuconfig USBDEV_COMPOSITE - bool "USB composite device support" - default n - ---help--- - Enables USB composite device support - -if USBDEV_COMPOSITE - -#config COMPOSITE_IAD -# bool "" -# default n -# ---help--- -# If one of the members of the composite has multiple interfaces -# (such as CDC/ACM), then an Interface Association Descriptor (IAD) -# will be necessary. Default: IAD will be used automatically if -# needed. It should not be necessary to set this. - -config COMPOSITE_EP0MAXPACKET - int "Max packet size for endpoint 0" - default 64 - ---help--- - Max packet size for endpoint 0 - -config COMPOSITE_VENDORID - hex "Composite vendor ID" - default 0 - -config COMPOSITE_VENDORSTR - string "Composite vendor ID" - default "Nuttx" - ---help--- - The vendor ID code/string - -config COMPOSITE_PRODUCTID - hex "Composite product id" - default 0 - -config COMPOSITE_PRODUCTSTR - string "Composite product string" - default "Composite device" - ---help--- - The product ID code/string - -config COMPOSITE_SERIALSTR - string "Composite serial string" - default "001" - ---help--- - Device serial number string - -config COMPOSITE_CONFIGSTR - string "Configuration string" - default "Nuttx COMPOSITE config" - ---help--- - Configuration string - -config COMPOSITE_VERSIONNO - string "Composite version number" - default "" - ---help--- - Interface version number. -endif - -menuconfig PL2303 - bool "Prolific PL2303 serial/USB converter emulation" - default n - select SERIAL_REMOVABLE - ---help--- - This logic emulates the Prolific PL2303 serial/USB converter - -if PL2303 - -config PL2303_CONSOLE - bool "PL2303 console device" - default n - ---help--- - Register the USB device as /dev/console so that is will be used - as the console device. - -config PL2303_EPINTIN - int "Logical endpoint numbers" - default 1 - -config PL2303_EPBULKOUT - int "Endpoint Bulkout" - default 2 - -config PL2303_EPBULKIN - int "Endpoint Bulkin" - default 3 - -config PL2303_EP0MAXPACKET - int "Packet and request buffer sizes" - default 64 - -config PL2303_NWRREQS - int "Number of read requests that can be in flight" - default 4 - ---help--- - The number of read requests that can be in flight - -config PL2303_NRDREQS - int "Number of write requests that can be in flight" - default 4 - ---help--- - The number of write/read requests that can be in flight - -config PL2303_RXBUFSIZE - int "Receive buffer size" - default 256 - ---help--- - Size of the serial receive/transmit buffers - -config PL2303_TXBUFSIZE - int "Transmit buffer size" - default 256 - ---help--- - Size of the serial receive/transmit buffers - -config PL2303_VENDORID - hex "Vendor ID" - default 0x067b - -config PL2303_PRODUCTID - hex "Product ID" - default 0x2303 - -config PL2303_VENDORSTR - string "Vendor string" - default "NuttX" - -config PL2303_PRODUCTSTR - string "Product string" - default "PL2303 Emulation" -endif - -menuconfig CDCACM - bool "USB Modem (CDC ACM) support" - default n - select SERIAL_REMOVABLE - ---help--- - Enables USB Modem (CDC ACM) support - -if CDCACM - -config CDCACM_CONSOLE - bool "CDC/ACM console device" - default n - ---help--- - Register the USB device as /dev/console so that is will be used - as the console device. - -config CDCACM_COMPOSITE - bool "CDC/ACM composite support" - default n - depends on USBDEV_COMPOSITE - ---help--- - Configure the CDC serial driver as part of a composite driver - (only if CONFIG_USBDEV_COMPOSITE is also defined) - -config CDCACM_IFNOBASE - int "Offset the CDC/ACM interface numbers" - default 0 - depends on CDCACM_COMPOSITE - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the CDC/ACM interface numbers so that they are - unique and contiguous. When used with the Mass Storage driver, the - correct value for this offset is zero. - -config CDCACM_STRBASE - int "Offset the CDC/ACM string numbers" - default 0 - depends on CDCACM_COMPOSITE - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the CDC/ACM string numbers so that they are - unique and contiguous. When used with the Mass Storage driver, the - correct value for this offset is four (this value actuallly only needs - to be defined if names are provided for the Notification interface, - config CDCACM_NOTIFSTR, or the data interface, CONFIG_CDCACM_DATAIFSTR). - -config CDCACM_EP0MAXPACKET - int "Endpoint 0 max packet size" - default 64 - ---help--- - Endpoint 0 max packet size. Default 64. - -config CDCACM_EPINTIN - int "Hardware endpoint that supports interrupt IN operation" - default 1 - ---help--- - The logical 7-bit address of a hardware endpoint that supports - interrupt IN operation. Default 1. - -config CDCACM_EPINTIN_FSSIZE - int "Endpoint in full speed size" - default 64 - ---help--- - Max package size for the interrupt IN endpoint if full speed mode. - Default 64. - -config CDCACM_EPINTIN_HSSIZE - int "Endpoint in high speed size" - default 64 - ---help--- - Max package size for the interrupt IN endpoint if high speed mode. - Default 64. - -config CDCACM_EPBULKOUT - int "Endpoint bulk out" - default 3 - ---help--- - The logical 7-bit address of a hardware endpoint that supports - bulk OUT operation. Default: 3 - -config CDCACM_EPBULKOUT_FSSIZE - int "Endpoint bulk out full speed size" - default 64 - ---help--- - Max package size for the bulk OUT endpoint if full speed mode. - Default 64. - -config CDCACM_EPBULKOUT_HSSIZE - int "Endpoint bulk out high speed size" - default 512 - ---help--- - Max package size for the bulk OUT endpoint if high speed mode. - Default 512. - -config CDCACM_EPBULKIN - int "Endpoint bulk in" - default 2 - ---help--- - The logical 7-bit address of a hardware endpoint that supports - bulk IN operation. Default: 2 - -config CDCACM_EPBULKIN_FSSIZE - int "Endpoint bulk in full speed size" - default 64 - ---help--- - Max package size for the bulk IN endpoint if full speed mode. - Default 64. - -config CDCACM_EPBULKIN_HSSIZE - int "Endpoint bulk in high speed size" - default 512 - ---help--- - Max package size for the bulk IN endpoint if high speed mode. - Default 512. - -config CDCACM_NWRREQS - int "Number of read requests that can be in flight" - default 4 - ---help--- - The number of read requests that can be in flight - -config CDCACM_NRDREQS - int "Number of write requests that can be in flight" - default 4 - ---help--- - The number of write/read requests that can be in flight - -config CDCACM_RXBUFSIZE - int "Receive buffer size" - default 256 - ---help--- - Size of the serial receive/transmit buffers - -config CDCACM_TXBUFSIZE - int "Transmit buffer size" - default 256 - ---help--- - Size of the serial receive/transmit buffers - -config CDCACM_VENDORID - hex "Vendor ID" - default 0x0525 - ---help--- - The vendor ID code/string. Default 0x0525 and "NuttX" - 0x0525 is the Netchip vendor and should not be used in any - products. This default VID was selected for compatibility with - the Linux CDC ACM default VID. - -config CDCACM_PRODUCTID - hex "Product ID" - default 0xa4a7 - ---help--- - The product ID code/string. Default 0xa4a7 and "CDC/ACM Serial" - 0xa4a7 was selected for compatibility with the Linux CDC ACM - default PID. - -config CDCACM_VENDORSTR - string "Vendor string" - default "NuttX" - -config CDCACM_PRODUCTSTR - string "Product string" - default "CDC/ACM Serial" -endif - -menuconfig USBMSC - bool "USB Mass storage class device" - default n - ---help--- - References: - "Universal Serial Bus Mass Storage Class, Specification Overview," - Revision 1.2, USB Implementer's Forum, June 23, 2003. - - "Universal Serial Bus Mass Storage Class, Bulk-Only Transport," - Revision 1.0, USB Implementer's Forum, September 31, 1999. - - "SCSI Primary Commands - 3 (SPC-3)," American National Standard - for Information Technology, May 4, 2005 - - "SCSI Primary Commands - 4 (SPC-4)," American National Standard - for Information Technology, July 19, 2008 - - "SCSI Block Commands -2 (SBC-2)," American National Standard - for Information Technology, November 13, 2004 - - "SCSI Multimedia Commands - 3 (MMC-3)," American National Standard - for Information Technology, November 12, 2001 - -if USBMSC -config USBMSC_COMPOSITE - bool "Mass storage composite support" - default n - depends on USBDEV_COMPOSITE - ---help--- - Configure the mass storage driver as part of a composite driver - (only if CONFIG_USBDEV_COMPOSITE is also defined) - -config USBMSC_IFNOBASE - int "Offset the mass storage interface number" - default 2 - depends on USBMSC_COMPOSITE - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the mass storage interface number so that it is - unique and contiguous. When used with the CDC/ACM driver, the - correct value for this offset is two (because of the two CDC/ACM - interfaces that will precede it). - -config USBMSC_STRBASE - int "Offset the mass storage string numbers" - default 2 - depends on USBMSC_COMPOSITE - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the mass storage string numbers so that they are - unique and contiguous. When used with the CDC/ACM driver, the - correct value for this offset is four (or perhaps 5 or 6, depending - on if CONFIG_CDCACM_NOTIFSTR or CONFIG_CDCACM_DATAIFSTR are defined). - -config USBMSC_EP0MAXPACKET - int "Max packet size for endpoint 0" - default 64 - ---help--- - Max packet size for endpoint 0 - -config USBMSC_EPBULKOUT - int "Endpoint bulk out" - default 0 - ---help--- - The logical 7-bit address of a hardware endpoints that support - bulk OUT and IN operations - -config USBMSC_EPBULKIN - int "Endpoint bulk in" - default 0 - ---help--- - The logical 7-bit address of a hardware endpoints that support - bulk OUT and IN operations - -config USBMSC_NWRREQS - int "The number of write requests that can be in flight" - default 4 - ---help--- - The number of write/read requests that can be in flight -config USBMSC_NRDREQS - int "The number of read requests that can be in flight" - default 4 - ---help--- - The number of write/read requests that can be in flight - -config USBMSC_BULKINREQLEN - int "Bulk in request size" - default 512 - -config USBMSC_BULKOUTREQLEN - int "Bulk out request size" - default 512 - ---help--- - The size of the buffer in each write/read request. This - value needs to be at least as large as the endpoint - maxpacket and ideally as large as a block device sector. - -config USBMSC_VENDORID - hex "Mass stroage Vendor ID" - default 0x00 - -config USBMSC_VENDORSTR - string "Mass stroage vendor string" - default "Nuttx" - ---help--- - The vendor ID code/string - -config USBMSC_PRODUCTID - hex "Mass stroage Product ID" - default 0x00 - -config USBMSC_PRODUCTSTR - string "Mass storage product string" - default "Mass Storage" - -config USBMSC_VERSIONNO - hex "USB MSC Version Number" - default "0x399" - -config USBMSC_REMOVABLE - bool "Mass stroage remove able" - default n - ---help--- - Select if the media is removable - USB Composite Device Configuration -endif diff --git a/nuttx/drivers/usbdev/Make.defs b/nuttx/drivers/usbdev/Make.defs deleted file mode 100644 index e43693b29..000000000 --- a/nuttx/drivers/usbdev/Make.defs +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################ -# drivers/usbdev/Make.defs -# -# Copyright (C) 2008, 2010-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -ifeq ($(CONFIG_USBDEV),y) - -# Include USB device drivers - -ifeq ($(CONFIG_PL2303),y) - CSRCS += pl2303.c -endif - -ifeq ($(CONFIG_CDCACM),y) - CSRCS += cdcacm.c cdcacm_desc.c -endif - -ifeq ($(CONFIG_USBMSC),y) - CSRCS += usbmsc.c usbmsc_desc.c usbmsc_scsi.c -endif - -ifeq ($(CONFIG_USBDEV_COMPOSITE),y) - CSRCS += composite.c composite_desc.c -endif - -CSRCS += usbdev_trace.c usbdev_trprintf.c - -# Include USB device build support - -DEPPATH += --dep-path usbdev -VPATH += :usbdev -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)usbdev} -endif diff --git a/nuttx/drivers/usbdev/cdcacm.c b/nuttx/drivers/usbdev/cdcacm.c deleted file mode 100644 index cb8679976..000000000 --- a/nuttx/drivers/usbdev/cdcacm.c +++ /dev/null @@ -1,2329 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/cdcacm.c - * - * Copyright (C) 2011-2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "cdcacm.h" - -#ifdef CONFIG_USBMSC_COMPOSITE -# include -# include "composite.h" -#endif - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Container to support a list of requests */ - -struct cdcacm_req_s -{ - FAR struct cdcacm_req_s *flink; /* Implements a singly linked list */ - FAR struct usbdev_req_s *req; /* The contained request */ -}; - -/* This structure describes the internal state of the driver */ - -struct cdcacm_dev_s -{ - FAR struct uart_dev_s serdev; /* Serial device structure */ - FAR struct usbdev_s *usbdev; /* usbdev driver pointer */ - - uint8_t config; /* Configuration number */ - uint8_t nwrq; /* Number of queue write requests (in reqlist)*/ - uint8_t nrdq; /* Number of queue read requests (in epbulkout) */ - uint8_t minor; /* The device minor number */ - bool rxenabled; /* true: UART RX "interrupts" enabled */ - int16_t rxhead; /* Working head; used when rx int disabled */ - - uint8_t ctrlline; /* Buffered control line state */ - struct cdc_linecoding_s linecoding; /* Buffered line status */ - cdcacm_callback_t callback; /* Serial event callback function */ - - FAR struct usbdev_ep_s *epintin; /* Interrupt IN endpoint structure */ - FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */ - FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */ - FAR struct usbdev_req_s *ctrlreq; /* Allocoated control request */ - struct sq_queue_s reqlist; /* List of write request containers */ - - /* Pre-allocated write request containers. The write requests will - * be linked in a free list (reqlist), and used to send requests to - * EPBULKIN; Read requests will be queued in the EBULKOUT. - */ - - struct cdcacm_req_s wrreqs[CONFIG_CDCACM_NWRREQS]; - struct cdcacm_req_s rdreqs[CONFIG_CDCACM_NWRREQS]; - - /* Serial I/O buffers */ - - char rxbuffer[CONFIG_CDCACM_RXBUFSIZE]; - char txbuffer[CONFIG_CDCACM_TXBUFSIZE]; -}; - -/* The internal version of the class driver */ - -struct cdcacm_driver_s -{ - struct usbdevclass_driver_s drvr; - FAR struct cdcacm_dev_s *dev; -}; - -/* This is what is allocated */ - -struct cdcacm_alloc_s -{ - struct cdcacm_dev_s dev; - struct cdcacm_driver_s drvr; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Transfer helpers *********************************************************/ - -static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, - uint8_t *reqbuf, uint16_t reqlen); -static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv); -static inline int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv, - uint8_t *reqbuf, uint16_t reqlen); - -/* Request helpers *********************************************************/ - -static struct usbdev_req_s *cdcacm_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len); -static void cdcacm_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/* Configuration ***********************************************************/ - -static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv); -#ifdef CONFIG_USBDEV_DUALSPEED -static int cdcacm_epconfigure(FAR struct usbdev_ep_s *ep, - enum cdcacm_epdesc_e epid, uint16_t mxpacket, bool last); -#endif -static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, - uint8_t config); - -/* Completion event handlers ***********************************************/ - -static void cdcacm_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); -static void cdcacm_rdcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); -static void cdcacm_wrcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/* USB class device ********************************************************/ - -static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void cdcacm_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, - size_t outlen); -static void cdcacm_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -#ifdef CONFIG_SERIAL_REMOVABLE -static void cdcacm_suspend(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void cdcacm_resume(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -#endif - -/* UART Operations **********************************************************/ - -static int cdcuart_setup(FAR struct uart_dev_s *dev); -static void cdcuart_shutdown(FAR struct uart_dev_s *dev); -static int cdcuart_attach(FAR struct uart_dev_s *dev); -static void cdcuart_detach(FAR struct uart_dev_s *dev); -static int cdcuart_ioctl(FAR struct file *filep,int cmd,unsigned long arg); -static void cdcuart_rxint(FAR struct uart_dev_s *dev, bool enable); -static void cdcuart_txint(FAR struct uart_dev_s *dev, bool enable); -static bool cdcuart_txempty(FAR struct uart_dev_s *dev); - -/**************************************************************************** - * Private Variables - ****************************************************************************/ -/* USB class device *********************************************************/ - -static const struct usbdevclass_driverops_s g_driverops = -{ - cdcacm_bind, /* bind */ - cdcacm_unbind, /* unbind */ - cdcacm_setup, /* setup */ - cdcacm_disconnect, /* disconnect */ -#ifdef CONFIG_SERIAL_REMOVABLE - cdcacm_suspend, /* suspend */ - cdcacm_resume, /* resume */ -#else - NULL, /* suspend */ - NULL, /* resume */ -#endif -}; - -/* Serial port **************************************************************/ - -static const struct uart_ops_s g_uartops = -{ - cdcuart_setup, /* setup */ - cdcuart_shutdown, /* shutdown */ - cdcuart_attach, /* attach */ - cdcuart_detach, /* detach */ - cdcuart_ioctl, /* ioctl */ - NULL, /* receive */ - cdcuart_rxint, /* rxinit */ - NULL, /* rxavailable */ - NULL, /* send */ - cdcuart_txint, /* txinit */ - NULL, /* txready */ - cdcuart_txempty /* txempty */ -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: cdcacm_fillrequest - * - * Description: - * If there is data to send it is copied to the given buffer. Called - * either to initiate the first write operation, or from the completion - * interrupt handler service consecutive write operations. - * - * NOTE: The USB serial driver does not use the serial drivers - * uart_xmitchars() API. That logic is essentially duplicated here because - * unlike UART hardware, we need to be able to handle writes not byte-by-byte, - * but packet-by-packet. Unfortunately, that decision also exposes some - * internals of the serial driver in the following. - * - ****************************************************************************/ - -static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, uint8_t *reqbuf, - uint16_t reqlen) -{ - FAR uart_dev_t *serdev = &priv->serdev; - FAR struct uart_buffer_s *xmit = &serdev->xmit; - irqstate_t flags; - uint16_t nbytes = 0; - - /* Disable interrupts */ - - flags = irqsave(); - - /* Transfer bytes while we have bytes available and there is room in the request */ - - while (xmit->head != xmit->tail && nbytes < reqlen) - { - *reqbuf++ = xmit->buffer[xmit->tail]; - nbytes++; - - /* Increment the tail pointer */ - - if (++(xmit->tail) >= xmit->size) - { - xmit->tail = 0; - } - } - - /* When all of the characters have been sent from the buffer - * disable the "TX interrupt". - */ - - if (xmit->head == xmit->tail) - { - uart_disabletxint(serdev); - } - - /* If any bytes were removed from the buffer, inform any waiters - * there there is space available. - */ - - if (nbytes) - { - uart_datasent(serdev); - } - - irqrestore(flags); - return nbytes; -} - -/**************************************************************************** - * Name: cdcacm_sndpacket - * - * Description: - * This function obtains write requests, transfers the TX data into the - * request, and submits the requests to the USB controller. This continues - * untils either (1) there are no further packets available, or (2) thre is - * no further data to send. - * - ****************************************************************************/ - -static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv) -{ - FAR struct usbdev_ep_s *ep; - FAR struct usbdev_req_s *req; - FAR struct cdcacm_req_s *reqcontainer; - uint16_t reqlen; - irqstate_t flags; - int len; - int ret = OK; - -#ifdef CONFIG_DEBUG - if (priv == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -ENODEV; - } -#endif - - flags = irqsave(); - - /* Use our IN endpoint for the transfer */ - - ep = priv->epbulkin; - - /* Loop until either (1) we run out or write requests, or (2) cdcacm_fillrequest() - * is unable to fill the request with data (i.e., until there is no more data - * to be sent). - */ - - uvdbg("head=%d tail=%d nwrq=%d empty=%d\n", - priv->serdev.xmit.head, priv->serdev.xmit.tail, - priv->nwrq, sq_empty(&priv->reqlist)); - - /* Get the maximum number of bytes that will fit into one bulk IN request */ - -#ifdef CONFIG_CDCACM_BULKREQLEN - reqlen = MAX(CONFIG_CDCACM_BULKREQLEN, ep->maxpacket); -#else - reqlen = ep->maxpacket; -#endif - - while (!sq_empty(&priv->reqlist)) - { - /* Peek at the request in the container at the head of the list */ - - reqcontainer = (struct cdcacm_req_s *)sq_peek(&priv->reqlist); - req = reqcontainer->req; - - /* Fill the request with serial TX data */ - - len = cdcacm_fillrequest(priv, req->buf, reqlen); - if (len > 0) - { - /* Remove the empty container from the request list */ - - (void)sq_remfirst(&priv->reqlist); - priv->nwrq--; - - /* Then submit the request to the endpoint */ - - req->len = len; - req->priv = reqcontainer; - req->flags = USBDEV_REQFLAGS_NULLPKT; - ret = EP_SUBMIT(ep, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), (uint16_t)-ret); - break; - } - } - else - { - break; - } - } - - irqrestore(flags); - return ret; -} - -/**************************************************************************** - * Name: cdcacm_recvpacket - * - * Description: - * A normal completion event was received by the read completion handler - * at the interrupt level (with interrupts disabled). This function handles - * the USB packet and provides the received data to the uart RX buffer. - * - * Assumptions: - * Called from the USB interrupt handler with interrupts disabled. - * - ****************************************************************************/ - -static inline int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv, - uint8_t *reqbuf, uint16_t reqlen) -{ - FAR uart_dev_t *serdev = &priv->serdev; - FAR struct uart_buffer_s *recv = &serdev->recv; - uint16_t currhead; - uint16_t nexthead; - uint16_t nbytes = 0; - - uvdbg("head=%d tail=%d nrdq=%d reqlen=%d\n", - priv->serdev.recv.head, priv->serdev.recv.tail, priv->nrdq, reqlen); - - /* Get the next head index. During the time that RX interrupts are disabled, the - * the serial driver will be extracting data from the circular buffer and modifying - * recv.tail. During this time, we should avoid modifying recv.head; Instead we will - * use a shadow copy of the index. When interrupts are restored, the real recv.head - * will be updated with this indes. - */ - - if (priv->rxenabled) - { - currhead = recv->head; - } - else - { - currhead = priv->rxhead; - } - - /* Pre-calculate the head index and check for wrap around. We need to do this - * so that we can determine if the circular buffer will overrun BEFORE we - * overrun the buffer! - */ - - nexthead = currhead + 1; - if (nexthead >= recv->size) - { - nexthead = 0; - } - - /* Then copy data into the RX buffer until either: (1) all of the data has been - * copied, or (2) the RX buffer is full. NOTE: If the RX buffer becomes full, - * then we have overrun the serial driver and data will be lost. - */ - - while (nexthead != recv->tail && nbytes < reqlen) - { - /* Copy one byte to the head of the circular RX buffer */ - - recv->buffer[currhead] = *reqbuf++; - - /* Update counts and indices */ - - currhead = nexthead; - nbytes++; - - /* Increment the head index and check for wrap around */ - - nexthead = currhead + 1; - if (nexthead >= recv->size) - { - nexthead = 0; - } - } - - /* Write back the head pointer using the shadow index if RX "interrupts" - * are disabled. - */ - - if (priv->rxenabled) - { - recv->head = currhead; - } - else - { - priv->rxhead = currhead; - } - - /* If data was added to the incoming serial buffer, then wake up any - * threads is waiting for incoming data. If we are running in an interrupt - * handler, then the serial driver will not run until the interrupt handler - * returns. - */ - - if (priv->rxenabled && nbytes > 0) - { - uart_datareceived(serdev); - } - - /* Return an error if the entire packet could not be transferred */ - - if (nbytes < reqlen) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RXOVERRUN), 0); - return -ENOSPC; - } - return OK; -} - -/**************************************************************************** - * Name: cdcacm_allocreq - * - * Description: - * Allocate a request instance along with its buffer - * - ****************************************************************************/ - -static struct usbdev_req_s *cdcacm_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len) -{ - FAR struct usbdev_req_s *req; - - req = EP_ALLOCREQ(ep); - if (req != NULL) - { - req->len = len; - req->buf = EP_ALLOCBUFFER(ep, len); - if (!req->buf) - { - EP_FREEREQ(ep, req); - req = NULL; - } - } - return req; -} - -/**************************************************************************** - * Name: cdcacm_freereq - * - * Description: - * Free a request instance along with its buffer - * - ****************************************************************************/ - -static void cdcacm_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - if (ep != NULL && req != NULL) - { - if (req->buf != NULL) - { - EP_FREEBUFFER(ep, req->buf); - } - EP_FREEREQ(ep, req); - } -} - -/**************************************************************************** - * Name: cdcacm_resetconfig - * - * Description: - * Mark the device as not configured and disable all endpoints. - * - ****************************************************************************/ - -static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv) -{ - /* Are we configured? */ - - if (priv->config != CDCACM_CONFIGIDNONE) - { - /* Yes.. but not anymore */ - - priv->config = CDCACM_CONFIGIDNONE; - - /* Inform the "upper half" driver that there is no (functional) USB - * connection. - */ - -#ifdef CONFIG_SERIAL_REMOVABLE - uart_connected(&priv->serdev, false); -#endif - - /* Disable endpoints. This should force completion of all pending - * transfers. - */ - - EP_DISABLE(priv->epintin); - EP_DISABLE(priv->epbulkin); - EP_DISABLE(priv->epbulkout); - } -} - -/**************************************************************************** - * Name: cdcacm_epconfigure - * - * Description: - * Configure one endpoint. - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -static int cdcacm_epconfigure(FAR struct usbdev_ep_s *ep, - enum cdcacm_epdesc_e epid, uint16_t mxpacket, - bool last) -{ - struct usb_epdesc_s epdesc; - cdcacm_mkepdesc(epid, mxpacket, &epdesc); - return EP_CONFIGURE(ep, &epdesc, last); -} -#endif - -/**************************************************************************** - * Name: cdcacm_setconfig - * - * Description: - * Set the device configuration by allocating and configuring endpoints and - * by allocating and queue read and write requests. - * - ****************************************************************************/ - -static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config) -{ - FAR struct usbdev_req_s *req; - int i; - int ret = 0; - -#if CONFIG_DEBUG - if (priv == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -EIO; - } -#endif - - if (config == priv->config) - { - /* Already configured -- Do nothing */ - - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALREADYCONFIGURED), 0); - return 0; - } - - /* Discard the previous configuration data */ - - cdcacm_resetconfig(priv); - - /* Was this a request to simply discard the current configuration? */ - - if (config == CDCACM_CONFIGIDNONE) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGNONE), 0); - return 0; - } - - /* We only accept one configuration */ - - if (config != CDCACM_CONFIGID) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGIDBAD), 0); - return -EINVAL; - } - - /* Configure the IN interrupt endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - if (priv->usbdev->speed == USB_SPEED_HIGH) - { - ret = cdcacm_epconfigure(priv->epintin, CDCACM_EPINTIN, - CONFIG_CDCACM_EPINTIN_HSSIZE, false); - } - else -#endif - { - ret = EP_CONFIGURE(priv->epintin, - cdcacm_getepdesc(CDCACM_EPINTIN), false); - } - - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINCONFIGFAIL), 0); - goto errout; - } - priv->epintin->priv = priv; - - /* Configure the IN bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - if (priv->usbdev->speed == USB_SPEED_HIGH) - { - ret = cdcacm_epconfigure(priv->epbulkin, CDCACM_EPBULKIN, - CONFIG_CDCACM_EPBULKIN_HSSIZE, false); - } - else -#endif - { - ret = EP_CONFIGURE(priv->epbulkin, - cdcacm_getepdesc(CDCACM_EPBULKIN), false); - } - - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkin->priv = priv; - - /* Configure the OUT bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - if (priv->usbdev->speed == USB_SPEED_HIGH) - { - ret = cdcacm_epconfigure(priv->epbulkout, CDCACM_EPBULKOUT, - CONFIG_CDCACM_EPBULKOUT_HSSIZE, true); - } - else -#endif - { - ret = EP_CONFIGURE(priv->epbulkout, - cdcacm_getepdesc(CDCACM_EPBULKOUT), true); - } - - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkout->priv = priv; - - /* Queue read requests in the bulk OUT endpoint */ - - DEBUGASSERT(priv->nrdq == 0); - for (i = 0; i < CONFIG_CDCACM_NRDREQS; i++) - { - req = priv->rdreqs[i].req; - req->callback = cdcacm_rdcomplete; - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-ret); - goto errout; - } - - priv->nrdq++; - } - - /* We are successfully configured */ - - priv->config = config; - - /* Inform the "upper half" driver that we are "open for business" */ - -#ifdef CONFIG_SERIAL_REMOVABLE - uart_connected(&priv->serdev, true); -#endif - - return OK; - -errout: - cdcacm_resetconfig(priv); - return ret; -} - -/**************************************************************************** - * Name: cdcacm_ep0incomplete - * - * Description: - * Handle completion of EP0 control operations - * - ****************************************************************************/ - -static void cdcacm_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - if (req->result || req->xfrd != req->len) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_REQRESULT), (uint16_t)-req->result); - } -} - -/**************************************************************************** - * Name: cdcacm_rdcomplete - * - * Description: - * Handle completion of read request on the bulk OUT endpoint. This - * is handled like the receipt of serial data on the "UART" - * - ****************************************************************************/ - -static void cdcacm_rdcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - FAR struct cdcacm_dev_s *priv; - irqstate_t flags; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct cdcacm_dev_s*)ep->priv; - - /* Process the received data unless this is some unusual condition */ - - flags = irqsave(); - switch (req->result) - { - case 0: /* Normal completion */ - usbtrace(TRACE_CLASSRDCOMPLETE, priv->nrdq); - cdcacm_recvpacket(priv, req->buf, req->xfrd); - break; - - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0); - priv->nrdq--; - irqrestore(flags); - return; - - default: /* Some other error occurred */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16_t)-req->result); - break; - }; - - /* Requeue the read request */ - -#ifdef CONFIG_CDCACM_BULKREQLEN - req->len = MAX(CONFIG_CDCACM_BULKREQLEN, ep->maxpacket); -#else - req->len = ep->maxpacket; -#endif - - ret = EP_SUBMIT(ep, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-req->result); - } - - irqrestore(flags); -} - -/**************************************************************************** - * Name: cdcacm_wrcomplete - * - * Description: - * Handle completion of write request. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -static void cdcacm_wrcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - FAR struct cdcacm_dev_s *priv; - FAR struct cdcacm_req_s *reqcontainer; - irqstate_t flags; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req || !req->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract references to our private data */ - - priv = (FAR struct cdcacm_dev_s *)ep->priv; - reqcontainer = (FAR struct cdcacm_req_s *)req->priv; - - /* Return the write request to the free list */ - - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); - priv->nwrq++; - irqrestore(flags); - - /* Send the next packet unless this was some unusual termination - * condition - */ - - switch (req->result) - { - case OK: /* Normal completion */ - usbtrace(TRACE_CLASSWRCOMPLETE, priv->nwrq); - cdcacm_sndpacket(priv); - break; - - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRSHUTDOWN), priv->nwrq); - break; - - default: /* Some other error occurred */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), (uint16_t)-req->result); - break; - } -} - -/**************************************************************************** - * USB Class Driver Methods - ****************************************************************************/ - -/**************************************************************************** - * Name: cdcacm_bind - * - * Description: - * Invoked when the driver is bound to a USB device driver - * - ****************************************************************************/ - -static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct cdcacm_dev_s *priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - FAR struct cdcacm_req_s *reqcontainer; - irqstate_t flags; - uint16_t reqlen; - int ret; - int i; - - usbtrace(TRACE_CLASSBIND, 0); - - /* Bind the structures */ - - priv->usbdev = dev; - - /* Save the reference to our private data structure in EP0 so that it - * can be recovered in ep0 completion events (Unless we are part of - * a composite device and, in that case, the composite device owns - * EP0). - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - dev->ep0->priv = priv; -#endif - - /* Preallocate control request */ - - priv->ctrlreq = cdcacm_allocreq(dev->ep0, CDCACM_MXDESCLEN); - if (priv->ctrlreq == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCCTRLREQ), 0); - ret = -ENOMEM; - goto errout; - } - - priv->ctrlreq->callback = cdcacm_ep0incomplete; - - /* Pre-allocate all endpoints... the endpoints will not be functional - * until the SET CONFIGURATION request is processed in cdcacm_setconfig. - * This is done here because there may be calls to kmalloc and the SET - * CONFIGURATION processing probably occurrs within interrupt handling - * logic where kmalloc calls will fail. - */ - - /* Pre-allocate the IN interrupt endpoint */ - - priv->epintin = DEV_ALLOCEP(dev, CDCACM_EPINTIN_ADDR, true, USB_EP_ATTR_XFER_INT); - if (!priv->epintin) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epintin->priv = priv; - - /* Pre-allocate the IN bulk endpoint */ - - priv->epbulkin = DEV_ALLOCEP(dev, CDCACM_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkin) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkin->priv = priv; - - /* Pre-allocate the OUT bulk endpoint */ - - priv->epbulkout = DEV_ALLOCEP(dev, CDCACM_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkout) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkout->priv = priv; - - /* Pre-allocate read requests */ - -#ifdef CONFIG_CDCACM_BULKREQLEN - reqlen = MAX(CONFIG_CDCACM_BULKREQLEN, priv->epbulkout->maxpacket); -#else - reqlen = priv->epbulkout->maxpacket; -#endif - - for (i = 0; i < CONFIG_CDCACM_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - reqcontainer->req = cdcacm_allocreq(priv->epbulkout, reqlen); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDALLOCREQ), -ENOMEM); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = cdcacm_rdcomplete; - } - - /* Pre-allocate write request containers and put in a free list */ - -#ifdef CONFIG_CDCACM_BULKREQLEN - reqlen = MAX(CONFIG_CDCACM_BULKREQLEN, priv->epbulkin->maxpacket); -#else - reqlen = priv->epbulkin->maxpacket; -#endif - - for (i = 0; i < CONFIG_CDCACM_NWRREQS; i++) - { - reqcontainer = &priv->wrreqs[i]; - reqcontainer->req = cdcacm_allocreq(priv->epbulkin, reqlen); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRALLOCREQ), -ENOMEM); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = cdcacm_wrcomplete; - - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); - priv->nwrq++; /* Count of write requests available */ - irqrestore(flags); - } - - /* Report if we are selfpowered (unless we are part of a composite device) */ - -#ifndef CONFIG_CDCACM_COMPOSITE -#ifdef CONFIG_USBDEV_SELFPOWERED - DEV_SETSELFPOWERED(dev); -#endif - - /* And pull-up the data line for the soft connect function (unless we are - * part of a composite device) - */ - - DEV_CONNECT(dev); -#endif - return OK; - -errout: - cdcacm_unbind(driver, dev); - return ret; -} - -/**************************************************************************** - * Name: cdcacm_unbind - * - * Description: - * Invoked when the driver is unbound from a USB device driver - * - ****************************************************************************/ - -static void cdcacm_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct cdcacm_dev_s *priv; - FAR struct cdcacm_req_s *reqcontainer; - irqstate_t flags; - int i; - - usbtrace(TRACE_CLASSUNBIND, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Make sure that we are not already unbound */ - - if (priv != NULL) - { - /* Make sure that the endpoints have been unconfigured. If - * we were terminated gracefully, then the configuration should - * already have been reset. If not, then calling cdcacm_resetconfig - * should cause the endpoints to immediately terminate all - * transfers and return the requests to us (with result == -ESHUTDOWN) - */ - - cdcacm_resetconfig(priv); - up_mdelay(50); - - /* Free the interrupt IN endpoint */ - - if (priv->epintin) - { - DEV_FREEEP(dev, priv->epintin); - priv->epintin = NULL; - } - - /* Free the bulk IN endpoint */ - - if (priv->epbulkin) - { - DEV_FREEEP(dev, priv->epbulkin); - priv->epbulkin = NULL; - } - - /* Free the pre-allocated control request */ - - if (priv->ctrlreq != NULL) - { - cdcacm_freereq(dev->ep0, priv->ctrlreq); - priv->ctrlreq = NULL; - } - - /* Free pre-allocated read requests (which should all have - * been returned to the free list at this time -- we don't check) - */ - - DEBUGASSERT(priv->nrdq == 0); - for (i = 0; i < CONFIG_CDCACM_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - if (reqcontainer->req) - { - cdcacm_freereq(priv->epbulkout, reqcontainer->req); - reqcontainer->req = NULL; - } - } - - /* Free the bulk OUT endpoint */ - - if (priv->epbulkout) - { - DEV_FREEEP(dev, priv->epbulkout); - priv->epbulkout = NULL; - } - - /* Free write requests that are not in use (which should be all - * of them) - */ - - flags = irqsave(); - DEBUGASSERT(priv->nwrq == CONFIG_CDCACM_NWRREQS); - while (!sq_empty(&priv->reqlist)) - { - reqcontainer = (struct cdcacm_req_s *)sq_remfirst(&priv->reqlist); - if (reqcontainer->req != NULL) - { - cdcacm_freereq(priv->epbulkin, reqcontainer->req); - priv->nwrq--; /* Number of write requests queued */ - } - } - DEBUGASSERT(priv->nwrq == 0); - irqrestore(flags); - } - - /* Clear out all data in the circular buffer */ - - priv->serdev.xmit.head = 0; - priv->serdev.xmit.tail = 0; -} - -/**************************************************************************** - * Name: cdcacm_setup - * - * Description: - * Invoked for ep0 control requests. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, - FAR uint8_t *dataout, size_t outlen) -{ - FAR struct cdcacm_dev_s *priv; - FAR struct usbdev_req_s *ctrlreq; - uint16_t value; - uint16_t index; - uint16_t len; - int ret = -EOPNOTSUPP; - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !ctrl) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -EIO; - } -#endif - - /* Extract reference to private data */ - - usbtrace(TRACE_CLASSSETUP, ctrl->req); - priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv || !priv->ctrlreq) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); - return -ENODEV; - } -#endif - ctrlreq = priv->ctrlreq; - - /* Extract the little-endian 16-bit values to host order */ - - value = GETUINT16(ctrl->value); - index = GETUINT16(ctrl->index); - len = GETUINT16(ctrl->len); - - uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", - ctrl->type, ctrl->req, value, index, len); - - if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) - { - /*********************************************************************** - * Standard Requests - ***********************************************************************/ - - switch (ctrl->req) - { - case USB_REQ_GETDESCRIPTOR: - { - /* The value field specifies the descriptor type in the MS byte and the - * descriptor index in the LS byte (order is little endian) - */ - - switch (ctrl->value[1]) - { - /* If the serial device is used in as part of a composite device, - * then the device descriptor is provided by logic in the composite - * device implementation. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE - case USB_DESC_TYPE_DEVICE: - { - ret = USB_SIZEOF_DEVDESC; - memcpy(ctrlreq->buf, cdcacm_getdevdesc(), ret); - } - break; -#endif - - /* If the serial device is used in as part of a composite device, - * then the device qualifier descriptor is provided by logic in the - * composite device implementation. - */ - -#if !defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) - case USB_DESC_TYPE_DEVICEQUALIFIER: - { - ret = USB_SIZEOF_QUALDESC; - memcpy(ctrlreq->buf, cdcacm_getqualdesc(), ret); - } - break; - - case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif - - /* If the serial device is used in as part of a composite device, - * then the configuration descriptor is provided by logic in the - * composite device implementation. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE - case USB_DESC_TYPE_CONFIG: - { -#ifdef CONFIG_USBDEV_DUALSPEED - ret = cdcacm_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req); -#else - ret = cdcacm_mkcfgdesc(ctrlreq->buf); -#endif - } - break; -#endif - - /* If the serial device is used in as part of a composite device, - * then the language string descriptor is provided by logic in the - * composite device implementation. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE - case USB_DESC_TYPE_STRING: - { - /* index == language code. */ - - ret = cdcacm_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); - } - break; -#endif - - default: - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_GETUNKNOWNDESC), value); - } - break; - } - } - break; - - case USB_REQ_SETCONFIGURATION: - { - if (ctrl->type == 0) - { - ret = cdcacm_setconfig(priv, value); - } - } - break; - - /* If the serial device is used in as part of a composite device, - * then the overall composite class configuration is managed by logic - * in the composite device implementation. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE - case USB_REQ_GETCONFIGURATION: - { - if (ctrl->type == USB_DIR_IN) - { - *(uint8_t*)ctrlreq->buf = priv->config; - ret = 1; - } - } - break; -#endif - - case USB_REQ_SETINTERFACE: - { - if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE && - priv->config == CDCACM_CONFIGID) - { - if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) || - (index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID)) - { - cdcacm_resetconfig(priv); - cdcacm_setconfig(priv, priv->config); - ret = 0; - } - } - } - break; - - case USB_REQ_GETINTERFACE: - { - if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) && - priv->config == CDCACM_CONFIGIDNONE) - { - if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) || - (index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID)) - { - *(uint8_t*) ctrlreq->buf = value; - ret = 1; - } - else - { - ret = -EDOM; - } - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); - break; - } - } - - else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS) - { - /*********************************************************************** - * CDC ACM-Specific Requests - ***********************************************************************/ - - switch (ctrl->req) - { - /* ACM_GET_LINE_CODING requests current DTE rate, stop-bits, parity, and - * number-of-character bits. (Optional) - */ - - case ACM_GET_LINE_CODING: - { - if (ctrl->type == (USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && - index == CDCACM_NOTIFID) - { - /* Return the current line status from the private data structure */ - - memcpy(ctrlreq->buf, &priv->linecoding, SIZEOF_CDC_LINECODING); - ret = SIZEOF_CDC_LINECODING; - } - else - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); - } - } - break; - - /* ACM_SET_LINE_CODING configures DTE rate, stop-bits, parity, and - * number-of-character bits. (Optional) - */ - - case ACM_SET_LINE_CODING: - { - if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && - len == SIZEOF_CDC_LINECODING && /* dataout && len == outlen && */ - index == CDCACM_NOTIFID) - { - /* Save the new line coding in the private data structure. NOTE: - * that this is conditional now because not all device controller - * drivers supported provisioni of EP0 OUT data with the setup - * command. - */ - - if (dataout && len <= SIZEOF_CDC_LINECODING) /* REVISIT */ - { - memcpy(&priv->linecoding, dataout, SIZEOF_CDC_LINECODING); - } - ret = 0; - - /* If there is a registered callback to receive line status info, then - * callout now. - */ - - if (priv->callback) - { - priv->callback(CDCACM_EVENT_LINECODING); - } - } - else - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); - } - } - break; - - /* ACM_SET_CTRL_LINE_STATE: RS-232 signal used to tell the DCE device the - * DTE device is now present. (Optional) - */ - - case ACM_SET_CTRL_LINE_STATE: - { - if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && - index == CDCACM_NOTIFID) - { - /* Save the control line state in the private data structure. Only bits - * 0 and 1 have meaning. - */ - - priv->ctrlline = value & 3; - ret = 0; - - /* If there is a registered callback to receive control line status info, - * then callout now. - */ - - if (priv->callback) - { - priv->callback(CDCACM_EVENT_CTRLLINE); - } - } - else - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); - } - } - break; - - /* Sends special carrier*/ - - case ACM_SEND_BREAK: - { - if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && - index == CDCACM_NOTIFID) - { - /* If there is a registered callback to handle the SendBreak request, - * then callout now. - */ - - ret = 0; - if (priv->callback) - { - priv->callback(CDCACM_EVENT_SENDBREAK); - } - } - else - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->req); - break; - } - } - else - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDTYPE), ctrl->type); - } - - /* Respond to the setup command if data was returned. On an error return - * value (ret < 0), the USB driver will stall. - */ - - if (ret >= 0) - { - /* Configure the response */ - - ctrlreq->len = MIN(len, ret); - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - - /* Send the response -- either directly to the USB controller or - * indirectly in the case where this class is a member of a composite - * device. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE - ret = EP_SUBMIT(dev->ep0, ctrlreq); -#else - ret = composite_ep0submit(driver, dev, ctrlreq); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPRESPQ), (uint16_t)-ret); - ctrlreq->result = OK; - cdcacm_ep0incomplete(dev->ep0, ctrlreq); - } - } - return ret; -} - -/**************************************************************************** - * Name: cdcacm_disconnect - * - * Description: - * Invoked after all transfers have been stopped, when the host is - * disconnected. This function is probably called from the context of an - * interrupt handler. - * - ****************************************************************************/ - -static void cdcacm_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct cdcacm_dev_s *priv; - irqstate_t flags; - - usbtrace(TRACE_CLASSDISCONNECT, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Inform the "upper half serial driver that we have lost the USB serial - * connection. - */ - - flags = irqsave(); -#ifdef CONFIG_SERIAL_REMOVABLE - uart_connected(&priv->serdev, false); -#endif - - /* Reset the configuration */ - - cdcacm_resetconfig(priv); - - /* Clear out all outgoing data in the circular buffer */ - - priv->serdev.xmit.head = 0; - priv->serdev.xmit.tail = 0; - irqrestore(flags); - - /* Perform the soft connect function so that we will we can be - * re-enumerated (unless we are part of a composite device) - */ - -#ifndef CONFIG_CDCACM_COMPOSITE - DEV_CONNECT(dev); -#endif -} - -/**************************************************************************** - * Name: cdcacm_suspend - * - * Description: - * Handle the USB suspend event. - * - ****************************************************************************/ - -#ifdef CONFIG_SERIAL_REMOVABLE -static void cdcacm_suspend(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct cdcacm_dev_s *priv; - - usbtrace(TRACE_CLASSSUSPEND, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - - /* And let the "upper half" driver now that we are suspended */ - - uart_connected(&priv->serdev, false); -} -#endif - -/**************************************************************************** - * Name: cdcacm_resume - * - * Description: - * Handle the USB resume event. - * - ****************************************************************************/ - -#ifdef CONFIG_SERIAL_REMOVABLE -static void cdcacm_resume(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct cdcacm_dev_s *priv; - - usbtrace(TRACE_CLASSRESUME, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - - /* Are we still configured? */ - - if (priv->config != CDCACM_CONFIGIDNONE) - { - /* Yes.. let the "upper half" know that have resumed */ - - uart_connected(&priv->serdev, true); - } -} -#endif - -/**************************************************************************** - * Serial Device Methods - ****************************************************************************/ - -/**************************************************************************** - * Name: cdcuart_setup - * - * Description: - * This method is called the first time that the serial port is opened. - * - ****************************************************************************/ - -static int cdcuart_setup(FAR struct uart_dev_s *dev) -{ - FAR struct cdcacm_dev_s *priv; - - usbtrace(CDCACM_CLASSAPI_SETUP, 0); - - /* Sanity check */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -EIO; - } -#endif - - /* Extract reference to private data */ - - priv = (FAR struct cdcacm_dev_s*)dev->priv; - - /* Check if we have been configured */ - - if (priv->config == CDCACM_CONFIGIDNONE) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SETUPNOTCONNECTED), 0); - return -ENOTCONN; - } - - return OK; -} - -/**************************************************************************** - * Name: cdcuart_shutdown - * - * Description: - * This method is called when the serial port is closed. This operation - * is very simple for the USB serial backend because the serial driver - * has already assured that the TX data has full drained -- it calls - * cdcuart_txempty() until that function returns true before calling this - * function. - * - ****************************************************************************/ - -static void cdcuart_shutdown(FAR struct uart_dev_s *dev) -{ - usbtrace(CDCACM_CLASSAPI_SHUTDOWN, 0); - - /* Sanity check */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - } -#endif -} - -/**************************************************************************** - * Name: cdcuart_attach - * - * Description: - * Does not apply to the USB serial class device - * - ****************************************************************************/ - -static int cdcuart_attach(FAR struct uart_dev_s *dev) -{ - usbtrace(CDCACM_CLASSAPI_ATTACH, 0); - return OK; -} - -/**************************************************************************** - * Name: cdcuart_detach - * - * Description: -* Does not apply to the USB serial class device - * - ****************************************************************************/ - -static void cdcuart_detach(FAR struct uart_dev_s *dev) -{ - usbtrace(CDCACM_CLASSAPI_DETACH, 0); -} - -/**************************************************************************** - * Name: cdcuart_ioctl - * - * Description: - * All ioctl calls will be routed through this method - * - ****************************************************************************/ - -static int cdcuart_ioctl(FAR struct file *filep,int cmd,unsigned long arg) -{ - struct inode *inode = filep->f_inode; - struct cdcacm_dev_s *priv = inode->i_private; - int ret = OK; - - switch (cmd) - { - /* CAICO_REGISTERCB - * Register a callback for serial event notification. Argument: - * cdcacm_callback_t. See cdcacm_callback_t type definition below. - * NOTE: The callback will most likely invoked at the interrupt level. - * The called back function should, therefore, limit its operations to - * invoking some kind of IPC to handle the serial event in some normal - * task environment. - */ - - case CAIOC_REGISTERCB: - { - /* Save the new callback function */ - - priv->callback = (cdcacm_callback_t)((uintptr_t)arg); - } - break; - - /* CAIOC_GETLINECODING - * Get current line coding. Argument: struct cdc_linecoding_s*. - * See include/nuttx/usb/cdc.h for structure definition. This IOCTL - * should be called to get the data associated with the - * CDCACM_EVENT_LINECODING event). - */ - - case CAIOC_GETLINECODING: - { - FAR struct cdc_linecoding_s *ptr = (FAR struct cdc_linecoding_s *)((uintptr_t)arg); - if (ptr) - { - memcpy(ptr, &priv->linecoding, sizeof(struct cdc_linecoding_s)); - } - else - { - ret = -EINVAL; - } - } - break; - - /* CAIOC_GETCTRLLINE - * Get control line status bits. Argument FAR int*. See - * include/nuttx/usb/cdc.h for bit definitions. This IOCTL should be - * called to get the data associated CDCACM_EVENT_CTRLLINE event. - */ - - case CAIOC_GETCTRLLINE: - { - FAR int *ptr = (FAR int *)((uintptr_t)arg); - if (ptr) - { - *ptr = priv->ctrlline; - } - else - { - ret = -EINVAL; - } - } - break; - - /* CAIOC_NOTIFY - * Send a serial state to the host via the Interrupt IN endpoint. - * Argument: int. This includes the current state of the carrier detect, - * DSR, break, and ring signal. See "Table 69: UART State Bitmap Values" - * and CDC_UART_definitions in include/nuttx/usb/cdc.h. - */ - - case CAIOC_NOTIFY: - { - /* Not yet implemented. I probably won't bother to implement until - * I comr up with a usage model that needs it. - * - * Here is what the needs to be done: - * - * 1. Format and send a request header with: - * - * bmRequestType: - * USB_REQ_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE - * bRequest: ACM_SERIAL_STATE - * wValue: 0 - * wIndex: 0 - * wLength: Length of data - * - * 2. Followed by the notification data (in a separate packet) - */ - - ret = -ENOSYS; - } - break; - - default: - ret = -ENOTTY; - break; - } - - return ret; -} - -/**************************************************************************** - * Name: cdcuart_rxint - * - * Description: - * Called by the serial driver to enable or disable RX interrupts. We, of - * course, have no RX interrupts but must behave consistently. This method - * is called under the conditions: - * - * 1. With enable==true when the port is opened (just after cdcuart_setup - * and cdcuart_attach are called called) - * 2. With enable==false while transferring data from the RX buffer - * 2. With enable==true while waiting for more incoming data - * 3. With enable==false when the port is closed (just before cdcuart_detach - * and cdcuart_shutdown are called). - * - ****************************************************************************/ - -static void cdcuart_rxint(FAR struct uart_dev_s *dev, bool enable) -{ - FAR struct cdcacm_dev_s *priv; - FAR uart_dev_t *serdev; - irqstate_t flags; - - usbtrace(CDCACM_CLASSAPI_RXINT, (uint16_t)enable); - - /* Sanity check */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = (FAR struct cdcacm_dev_s*)dev->priv; - serdev = &priv->serdev; - - /* We need exclusive access to the RX buffer and private structure - * in the following. - */ - - flags = irqsave(); - if (enable) - { - /* RX "interrupts" are enabled. Is this a transition from disabled - * to enabled state? - */ - - if (!priv->rxenabled) - { - /* Yes. During the time that RX interrupts are disabled, the - * the serial driver will be extracting data from the circular - * buffer and modifying recv.tail. During this time, we - * should avoid modifying recv.head; When interrupts are restored, - * we can update the head pointer for all of the data that we - * put into cicular buffer while "interrupts" were disabled. - */ - - if (priv->rxhead != serdev->recv.head) - { - serdev->recv.head = priv->rxhead; - - /* Yes... signal the availability of new data */ - - uart_datareceived(serdev); - } - - /* RX "interrupts are no longer disabled */ - - priv->rxenabled = true; - } - } - - /* RX "interrupts" are disabled. Is this a transition from enabled - * to disabled state? - */ - - else if (priv->rxenabled) - { - /* Yes. During the time that RX interrupts are disabled, the - * the serial driver will be extracting data from the circular - * buffer and modifying recv.tail. During this time, we - * should avoid modifying recv.head; When interrupts are disabled, - * we use a shadow index and continue adding data to the circular - * buffer. - */ - - priv->rxhead = serdev->recv.head; - priv->rxenabled = false; - } - irqrestore(flags); -} - -/**************************************************************************** - * Name: cdcuart_txint - * - * Description: - * Called by the serial driver to enable or disable TX interrupts. We, of - * course, have no TX interrupts but must behave consistently. Initially, - * TX interrupts are disabled. This method is called under the conditions: - * - * 1. With enable==false while transferring data into the TX buffer - * 2. With enable==true when data may be taken from the buffer. - * 3. With enable==false when the TX buffer is empty - * - ****************************************************************************/ - -static void cdcuart_txint(FAR struct uart_dev_s *dev, bool enable) -{ - FAR struct cdcacm_dev_s *priv; - - usbtrace(CDCACM_CLASSAPI_TXINT, (uint16_t)enable); - - /* Sanity checks */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct cdcacm_dev_s*)dev->priv; - - /* If the new state is enabled and if there is data in the XMIT buffer, - * send the next packet now. - */ - - uvdbg("enable=%d head=%d tail=%d\n", - enable, priv->serdev.xmit.head, priv->serdev.xmit.tail); - - if (enable && priv->serdev.xmit.head != priv->serdev.xmit.tail) - { - cdcacm_sndpacket(priv); - } -} - -/**************************************************************************** - * Name: cdcuart_txempty - * - * Description: - * Return true when all data has been sent. This is called from the - * serial driver when the driver is closed. It will call this API - * periodically until it reports true. NOTE that the serial driver takes all - * responsibility for flushing TX data through the hardware so we can be - * a bit sloppy about that. - * - ****************************************************************************/ - -static bool cdcuart_txempty(FAR struct uart_dev_s *dev) -{ - FAR struct cdcacm_dev_s *priv = (FAR struct cdcacm_dev_s*)dev->priv; - - usbtrace(CDCACM_CLASSAPI_TXEMPTY, 0); - -#if CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return true; - } -#endif - - /* When all of the allocated write requests have been returned to the - * reqlist, then there is no longer any TX data in flight. - */ - - return priv->nwrq >= CONFIG_CDCACM_NWRREQS; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: cdcacm_classobject - * - * Description: - * Register USB serial port (and USB serial console if so configured) and - * return the class object. - * - * Input Parameter: - * minor - Device minor number. E.g., minor 0 would correspond to - * /dev/ttyACM0. - * classdev - The location to return the CDC serial class' device - * instance. - * - * Returned Value: - * A pointer to the allocated class object (NULL on failure). - * - ****************************************************************************/ - -#ifndef CONFIG_CDCACM_COMPOSITE -static -#endif -int cdcacm_classobject(int minor, FAR struct usbdevclass_driver_s **classdev) -{ - FAR struct cdcacm_alloc_s *alloc; - FAR struct cdcacm_dev_s *priv; - FAR struct cdcacm_driver_s *drvr; - char devname[CDCACM_DEVNAME_SIZE]; - int ret; - - /* Allocate the structures needed */ - - alloc = (FAR struct cdcacm_alloc_s*)kmalloc(sizeof(struct cdcacm_alloc_s)); - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCDEVSTRUCT), 0); - return -ENOMEM; - } - - /* Convenience pointers into the allocated blob */ - - priv = &alloc->dev; - drvr = &alloc->drvr; - - /* Initialize the USB serial driver structure */ - - memset(priv, 0, sizeof(struct cdcacm_dev_s)); - sq_init(&priv->reqlist); - - priv->minor = minor; - - /* Fake line status */ - - priv->linecoding.baud[0] = (115200) & 0xff; /* Baud=115200 */ - priv->linecoding.baud[1] = (115200 >> 8) & 0xff; - priv->linecoding.baud[2] = (115200 >> 16) & 0xff; - priv->linecoding.baud[3] = (115200 >> 24) & 0xff; - priv->linecoding.stop = CDC_CHFMT_STOP1; /* One stop bit */ - priv->linecoding.parity = CDC_PARITY_NONE; /* No parity */ - priv->linecoding.nbits = 8; /* 8 data bits */ - - /* Initialize the serial driver sub-structure */ - - /* The initial state is disconnected */ - -#ifdef CONFIG_SERIAL_REMOVABLE - priv->serdev.disconnected = true; -#endif - priv->serdev.recv.size = CONFIG_CDCACM_RXBUFSIZE; - priv->serdev.recv.buffer = priv->rxbuffer; - priv->serdev.xmit.size = CONFIG_CDCACM_TXBUFSIZE; - priv->serdev.xmit.buffer = priv->txbuffer; - priv->serdev.ops = &g_uartops; - priv->serdev.priv = priv; - - /* Initialize the USB class driver structure */ - -#ifdef CONFIG_USBDEV_DUALSPEED - drvr->drvr.speed = USB_SPEED_HIGH; -#else - drvr->drvr.speed = USB_SPEED_FULL; -#endif - drvr->drvr.ops = &g_driverops; - drvr->dev = priv; - - /* Register the USB serial console */ - -#ifdef CONFIG_CDCACM_CONSOLE - priv->serdev.isconsole = true; - ret = uart_register("/dev/console", &priv->serdev); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONSOLEREGISTER), (uint16_t)-ret); - goto errout_with_class; - } -#endif - - /* Register the CDC/ACM TTY device */ - - sprintf(devname, CDCACM_DEVNAME_FORMAT, minor); - ret = uart_register(devname, &priv->serdev); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UARTREGISTER), (uint16_t)-ret); - goto errout_with_class; - } - - *classdev = &drvr->drvr; - return OK; - -errout_with_class: - kfree(alloc); - return ret; -} - -/**************************************************************************** - * Name: cdcacm_initialize - * - * Description: - * Register USB serial port (and USB serial console if so configured). - * - * Input Parameter: - * minor - Device minor number. E.g., minor 0 would correspond to - * /dev/ttyACM0. - * handle - An optional opaque reference to the CDC/ACM class object that - * may subsequently be used with cdcacm_uninitialize(). - * - * Returned Value: - * Zero (OK) means that the driver was successfully registered. On any - * failure, a negated errno value is retured. - * - ****************************************************************************/ - -#ifndef CONFIG_CDCACM_COMPOSITE -int cdcacm_initialize(int minor, FAR void **handle) -{ - FAR struct usbdevclass_driver_s *drvr = NULL; - int ret; - - /* Get an instance of the serial driver class object */ - - ret = cdcacm_classobject(minor, &drvr); - if (ret == OK) - { - /* Register the USB serial class driver */ - - ret = usbdev_register(drvr); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), (uint16_t)-ret); - } - } - - /* Return the driver instance (if any) if the caller has requested it - * by provided a pointer to the location to return it. - */ - - if (handle) - { - *handle = (FAR void*)drvr; - } - - return ret; -} -#endif - -/**************************************************************************** - * Name: cdcacm_uninitialize - * - * Description: - * Un-initialize the USB storage class driver. This function is used - * internally by the USB composite driver to unitialize the CDC/ACM - * driver. This same interface is available (with an untyped input - * parameter) when the CDC/ACM driver is used standalone. - * - * Input Parameters: - * There is one parameter, it differs in typing depending upon whether the - * CDC/ACM driver is an internal part of a composite device, or a standalone - * USB driver: - * - * classdev - The class object returned by board_cdcclassobject() or - * cdcacm_classobject() - * handle - The opaque handle represetning the class object returned by - * a previous call to cdcacm_initialize(). - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_CDCACM_COMPOSITE -void cdcacm_uninitialize(FAR struct usbdevclass_driver_s *classdev) -#else -void cdcacm_uninitialize(FAR void *handle) -#endif -{ -#ifdef CONFIG_CDCACM_COMPOSITE - FAR struct cdcacm_driver_s *drvr = (FAR struct cdcacm_driver_s *)classdev; -#else - FAR struct cdcacm_driver_s *drvr = (FAR struct cdcacm_driver_s *)handle; -#endif - FAR struct cdcacm_dev_s *priv = drvr->dev; - char devname[CDCACM_DEVNAME_SIZE]; - int ret; - - /* Un-register the CDC/ACM TTY device */ - - sprintf(devname, CDCACM_DEVNAME_FORMAT, priv->minor); - ret = unregister_driver(devname); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UARTUNREGISTER), (uint16_t)-ret); - } - - /* Unregister the driver (unless we are a part of a composite device). The - * device unregister logic will (1) return all of the requests to us then - * (2) all the unbind method. - * - * The same thing will happen in the composite case except that: (1) the - * composite driver will call usbdev_unregister() which will (2) return the - * requests for all members of the composite, and (3) call the unbind - * method in the composite device which will (4) call the unbind method - * for this device. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE - usbdev_unregister(&drvr->drvr); -#endif - - /* And free the driver structure */ - - kfree(priv); -} diff --git a/nuttx/drivers/usbdev/cdcacm.h b/nuttx/drivers/usbdev/cdcacm.h deleted file mode 100644 index 8b06ca9f3..000000000 --- a/nuttx/drivers/usbdev/cdcacm.h +++ /dev/null @@ -1,350 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/cdcacm.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_USBDEV_CDCACM_H -#define __DRIVERS_USBDEV_CDCACM_H 1 - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* If the serial device is configured as part of a composite device than both - * CONFIG_USBDEV_COMPOSITE and CONFIG_CDCACM_COMPOSITE must be defined. - */ - -#ifndef CONFIG_USBDEV_COMPOSITE -# undef CONFIG_CDCACM_COMPOSITE -#endif - -#if defined(CONFIG_CDCACM_COMPOSITE) && !defined(CONFIG_CDCACM_STRBASE) -# define CONFIG_CDCACM_STRBASE (4) -#endif - -#if defined(CONFIG_CDCACM_COMPOSITE) && !defined(CONFIG_COMPOSITE_IAD) -# warning "CONFIG_COMPOSITE_IAD may be needed" -#endif - -/* Packet and request buffer sizes */ - -#ifndef CONFIG_CDCACM_COMPOSITE -# ifndef CONFIG_CDCACM_EP0MAXPACKET -# define CONFIG_CDCACM_EP0MAXPACKET 64 -# endif -#endif - -/* Interface IDs. If the serial driver is built as a component of a composite - * device, then the interface IDs may need to be offset. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE -# undef CONFIG_CDCACM_IFNOBASE -# define CONFIG_CDCACM_IFNOBASE 0 -#endif - -#ifndef CONFIG_CDCACM_IFNOBASE -# define CONFIG_CDCACM_IFNOBASE 0 -#endif - -/* Descriptors **************************************************************/ -/* These settings are not modifiable via the NuttX configuration */ - -#define CDC_VERSIONNO 0x0110 /* CDC version number 1.10 (BCD) */ -#define CDCACM_CONFIGIDNONE (0) /* Config ID means to return to address mode */ - -/* Interface IDs: - * - * CDCACM_NINTERFACES Two interfaces - * CDCACM_NOTIFID ID of the notifier interface - * CDCACM_NOTALTIFID No alternate for the notifier interface - * CDCACM_DATAIFID ID of the data interface - * CDCACM_DATAALTIFID No alternate for the data interface - */ - -#define CDCACM_NINTERFACES (2) /* Number of interfaces in the configuration */ -#define CDCACM_NOTIFID (CONFIG_CDCACM_IFNOBASE+0) -#define CDCACM_NOTALTIFID (0) -#define CDCACM_DATAIFID (CONFIG_CDCACM_IFNOBASE+1) -#define CDCACM_DATAALTIFID (0) - -/* Configuration descriptor values */ - -#define CDCACM_CONFIGID (1) /* The only supported configuration ID */ - -/* Buffer big enough for any of our descriptors (the config descriptor is the - * biggest). - */ - -#define CDCACM_MXDESCLEN (64) - -/* Device descriptor values */ - -#define CDCACM_VERSIONNO (0x0101) /* Device version number 1.1 (BCD) */ -#define CDCACM_NCONFIGS (1) /* Number of configurations supported */ - -/* String language */ - -#define CDCACM_STR_LANGUAGE (0x0409) /* en-us */ - -/* Descriptor strings. If there serial device is part of a composite device - * then the manufacturer, product, and serial number strings will be provided - * by the composite logic. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE -# define CDCACM_MANUFACTURERSTRID (1) -# define CDCACM_PRODUCTSTRID (2) -# define CDCACM_SERIALSTRID (3) -# define CDCACM_CONFIGSTRID (4) - -# define CDCACM_LASTBASESTRID (4) -# undef CONFIG_CDCACM_STRBASE -# define CONFIG_CDCACM_STRBASE (0) -#else -# define CDCACM_LASTBASESTRID CONFIG_CDCACM_STRBASE -#endif - -/* These string IDs only exist if a user-defined string is provided */ - -#ifdef CONFIG_CDCACM_NOTIFSTR -# define CDCACM_NOTIFSTRID (CDCACM_LASTBASESTRID+1) -#else -# define CDCACM_NOTIFSTRID CDCACM_LASTBASESTRID -#endif - -#ifdef CONFIG_CDCACM_DATAIFSTR -# define CDCACM_DATAIFSTRID (CDCACM_NOTIFSTRID+1) -#else -# define CDCACM_DATAIFSTRID CDCACM_NOTIFSTRID -#endif - -#define CDCACM_LASTSTRID CDCACM_DATAIFSTRID -#define CDCACM_NSTRIDS (CDCACM_LASTSTRID - CONFIG_CDCACM_STRBASE) - -/* Configuration descriptor size */ - -#if !defined(CONFIG_CDCACM_COMPOSITE) - -/* Number of individual descriptors in the configuration descriptor: - * Configuration descriptor + (2) interface descriptors + (3) endpoint - * descriptors + (3) ACM descriptors. - */ - -# define CDCACM_CFGGROUP_SIZE (9) - -/* The size of the config descriptor: (9 + 2*9 + 3*7 + 4 + 5 + 5) = 62 */ - -# define SIZEOF_CDCACM_CFGDESC \ - (USB_SIZEOF_CFGDESC + 2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + \ - SIZEOF_ACM_FUNCDESC + SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1)) - -#elif defined(CONFIG_COMPOSITE_IAD) - -/* Number of individual descriptors in the configuration descriptor: - * (1) interface association descriptor + (2) interface descriptors + - * (3) endpoint descriptors + (3) ACM descriptors. - */ - -# define CDCACM_CFGGROUP_SIZE (9) - -/* The size of the config descriptor: (8 + 2*9 + 3*7 + 4 + 5 + 5) = 61 */ - -# define SIZEOF_CDCACM_CFGDESC \ - (USB_SIZEOF_IADDESC +2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + \ - SIZEOF_ACM_FUNCDESC + SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1)) - -#else - -/* Number of individual descriptors in the configuration descriptor: - * (2) interface descriptors + (3) endpoint descriptors + (3) ACM descriptors. - */ - -# define CDCACM_CFGGROUP_SIZE (8) - -/* The size of the config descriptor: (2*9 + 3*7 + 4 + 5 + 5) = 53 */ - -# define SIZEOF_CDCACM_CFGDESC \ - (2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + SIZEOF_ACM_FUNCDESC + \ - SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1)) -#endif - -/* Endpoint configuration ****************************************************/ - -#define CDCACM_EPINTIN_ADDR (USB_DIR_IN|CONFIG_CDCACM_EPINTIN) -#define CDCACM_EPINTIN_ATTR (USB_EP_ATTR_XFER_INT) - -#define CDCACM_EPOUTBULK_ADDR (CONFIG_CDCACM_EPBULKOUT) -#define CDCACM_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK) - -#define CDCACM_EPINBULK_ADDR (USB_DIR_IN|CONFIG_CDCACM_EPBULKIN) -#define CDCACM_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK) - -/* Device driver definitions ************************************************/ -/* A CDC/ACM device is specific by a minor number in the range of 0-255. - * This maps to a character device at /dev/ttyACMx, x=0..255. - */ - -#define CDCACM_DEVNAME_FORMAT "/dev/ttyACM%d" -#define CDCACM_DEVNAME_SIZE 16 - -/* Misc Macros **************************************************************/ -/* MIN/MAX macros */ - -#ifndef MIN -# define MIN(a,b) ((a)<(b)?(a):(b)) -#endif - -#ifndef MAX -# define MAX(a,b) ((a)>(b)?(a):(b)) -#endif - -/* Trace values *************************************************************/ - -#define CDCACM_CLASSAPI_SETUP TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SETUP) -#define CDCACM_CLASSAPI_SHUTDOWN TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SHUTDOWN) -#define CDCACM_CLASSAPI_ATTACH TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_ATTACH) -#define CDCACM_CLASSAPI_DETACH TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_DETACH) -#define CDCACM_CLASSAPI_IOCTL TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_IOCTL) -#define CDCACM_CLASSAPI_RECEIVE TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RECEIVE) -#define CDCACM_CLASSAPI_RXINT TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RXINT) -#define CDCACM_CLASSAPI_RXAVAILABLE TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RXAVAILABLE) -#define CDCACM_CLASSAPI_SEND TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SEND) -#define CDCACM_CLASSAPI_TXINT TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXINT) -#define CDCACM_CLASSAPI_TXREADY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXREADY) -#define CDCACM_CLASSAPI_TXEMPTY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXEMPTY) - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -enum cdcacm_epdesc_e -{ - CDCACM_EPINTIN = 0, /* Interrupt IN endpoint descriptor */ - CDCACM_EPBULKOUT, /* Bulk OUT endpoint descriptor */ - CDCACM_EPBULKIN /* Bulk IN endpoint descriptor */ -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Name: cdcacm_mkstrdesc - * - * Description: - * Construct a string descriptor - * - ****************************************************************************/ - -int cdcacm_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc); - -/**************************************************************************** - * Name: cdcacm_getepdesc - * - * Description: - * Return a pointer to the raw device descriptor - * - ****************************************************************************/ - -#ifndef CONFIG_CDCACM_COMPOSITE -FAR const struct usb_devdesc_s *cdcacm_getdevdesc(void); -#endif - -/**************************************************************************** - * Name: cdcacm_getepdesc - * - * Description: - * Return a pointer to the raw endpoint descriptor (used for configuring - * endpoints) - * - ****************************************************************************/ - -FAR const struct usb_epdesc_s *cdcacm_getepdesc(enum cdcacm_epdesc_e epid); - -/**************************************************************************** - * Name: cdcacm_mkepdesc - * - * Description: - * Construct the endpoint descriptor using the correct max packet size. - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -void cdcacm_mkepdesc(enum cdcacm_epdesc_e epid, - uint16_t mxpacket, FAR struct usb_epdesc_s *outdesc); -#endif - -/**************************************************************************** - * Name: cdcacm_mkcfgdesc - * - * Description: - * Construct the configuration descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, uint8_t speed, uint8_t type); -#else -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf); -#endif - -/**************************************************************************** - * Name: cdcacm_getqualdesc - * - * Description: - * Return a pointer to the raw qual descriptor - * - ****************************************************************************/ - -#if !defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) -FAR const struct usb_qualdesc_s *cdcacm_getqualdesc(void); -#endif - -#endif /* __DRIVERS_USBDEV_CDCACM_H */ diff --git a/nuttx/drivers/usbdev/cdcacm_desc.c b/nuttx/drivers/usbdev/cdcacm_desc.c deleted file mode 100644 index fde13bfd3..000000000 --- a/nuttx/drivers/usbdev/cdcacm_desc.c +++ /dev/null @@ -1,613 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/cdcacm_desc.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "cdcacm.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Describes one description in the group of descriptors forming the - * total configuration descriptor. - */ - -struct cfgdecsc_group_s -{ - uint16_t descsize; /* Size of the descriptor in bytes */ - uint16_t hsepsize; /* High speed max packet size */ - FAR void *desc; /* A pointer to the descriptor */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* USB descriptor templates these will be copied and modified **************/ -/* Device Descriptor. If the USB serial device is configured as part of - * composite device, then the device descriptor will be provided by the - * composite device logic. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE -static const struct usb_devdesc_s g_devdesc = -{ - USB_SIZEOF_DEVDESC, /* len */ - USB_DESC_TYPE_DEVICE, /* type */ - { /* usb */ - LSBYTE(0x0200), - MSBYTE(0x0200) - }, - USB_CLASS_CDC, /* class */ - CDC_SUBCLASS_NONE, /* subclass */ - CDC_PROTO_NONE, /* protocol */ - CONFIG_CDCACM_EP0MAXPACKET, /* maxpacketsize */ - { - LSBYTE(CONFIG_CDCACM_VENDORID), /* vendor */ - MSBYTE(CONFIG_CDCACM_VENDORID) - }, - { - LSBYTE(CONFIG_CDCACM_PRODUCTID), /* product */ - MSBYTE(CONFIG_CDCACM_PRODUCTID) - }, - { - LSBYTE(CDCACM_VERSIONNO), /* device */ - MSBYTE(CDCACM_VERSIONNO) - }, - CDCACM_MANUFACTURERSTRID, /* imfgr */ - CDCACM_PRODUCTSTRID, /* iproduct */ - CDCACM_SERIALSTRID, /* serno */ - CDCACM_NCONFIGS /* nconfigs */ -}; -#endif - -/* Configuration descriptor. If the USB serial device is configured as part of - * composite device, then the configuration descriptor will be provided by the - * composite device logic. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE -static const struct usb_cfgdesc_s g_cfgdesc = -{ - USB_SIZEOF_CFGDESC, /* len */ - USB_DESC_TYPE_CONFIG, /* type */ - { - LSBYTE(SIZEOF_CDCACM_CFGDESC), /* LS totallen */ - MSBYTE(SIZEOF_CDCACM_CFGDESC) /* MS totallen */ - }, - CDCACM_NINTERFACES, /* ninterfaces */ - CDCACM_CONFIGID, /* cfgvalue */ - CDCACM_CONFIGSTRID, /* icfg */ - USB_CONFIG_ATTR_ONE|SELFPOWERED|REMOTEWAKEUP, /* attr */ - (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */ -}; -#endif - -/* Interface association descriptor */ - -#if defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_COMPOSITE_IAD) -static const struct usb_iaddesc_s g_iaddesc = -{ - USB_SIZEOF_IADDESC, /* len */ - USB_DESC_TYPE_INTERFACEASSOCIATION, /* type */ - CONFIG_CDCACM_IFNOBASE, /* firstif */ - CDCACM_NINTERFACES, /* nifs */ - USB_CLASS_CDC, /* class */ - CDC_SUBCLASS_ACM, /* subclass */ - CDC_PROTO_NONE, /* protocol */ - 0 /* ifunction */ -}; -#endif - -/* Notification interface */ - -static const struct usb_ifdesc_s g_notifdesc = -{ - USB_SIZEOF_IFDESC, /* len */ - USB_DESC_TYPE_INTERFACE, /* type */ - CDCACM_NOTIFID, /* ifno */ - CDCACM_NOTALTIFID, /* alt */ - 1, /* neps */ - USB_CLASS_CDC, /* class */ - CDC_SUBCLASS_ACM, /* subclass */ - CDC_PROTO_ATM, /* proto */ -#ifdef CONFIG_CDCACM_NOTIFSTR - CDCACM_NOTIFSTRID /* iif */ -#else - 0 /* iif */ -#endif -}; - -/* Header functional descriptor */ - -static const struct cdc_hdr_funcdesc_s g_funchdr = -{ - SIZEOF_HDR_FUNCDESC, /* size */ - USB_DESC_TYPE_CSINTERFACE, /* type */ - CDC_DSUBTYPE_HDR, /* subtype */ - { - LSBYTE(CDC_VERSIONNO), /* LS cdc */ - MSBYTE(CDC_VERSIONNO) /* MS cdc */ - } -}; - -/* ACM functional descriptor */ - -static const struct cdc_acm_funcdesc_s g_acmfunc = -{ - SIZEOF_ACM_FUNCDESC, /* size */ - USB_DESC_TYPE_CSINTERFACE, /* type */ - CDC_DSUBTYPE_ACM, /* subtype */ - 0x06 /* caps */ -}; - -/* Union functional descriptor */ - -static const struct cdc_union_funcdesc_s g_unionfunc = -{ - SIZEOF_UNION_FUNCDESC(1), /* size */ - USB_DESC_TYPE_CSINTERFACE, /* type */ - CDC_DSUBTYPE_UNION, /* subtype */ - 0, /* master */ - {1} /* slave[0] */ -}; - -/* Interrupt IN endpoint descriptor */ - -static const struct usb_epdesc_s g_epintindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - CDCACM_EPINTIN_ADDR, /* addr */ - CDCACM_EPINTIN_ATTR, /* attr */ - { - LSBYTE(CONFIG_CDCACM_EPINTIN_FSSIZE), /* maxpacket (full speed) */ - MSBYTE(CONFIG_CDCACM_EPINTIN_FSSIZE) - }, - 0xff /* interval */ -}; - -/* Data interface descriptor */ - -static const struct usb_ifdesc_s g_dataifdesc = -{ - USB_SIZEOF_IFDESC, /* len */ - USB_DESC_TYPE_INTERFACE, /* type */ - CDCACM_DATAIFID, /* ifno */ - CDCACM_DATAALTIFID, /* alt */ - 2, /* neps */ - USB_CLASS_CDC_DATA, /* class */ - CDC_DATA_SUBCLASS_NONE, /* subclass */ - CDC_DATA_PROTO_NONE, /* proto */ -#ifdef CONFIG_CDCACM_DATAIFSTR - CDCACM_DATAIFSTRID /* iif */ -#else - 0 /* iif */ -#endif -}; - -/* Bulk OUT endpoint descriptor */ - -static const struct usb_epdesc_s g_epbulkoutdesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - CDCACM_EPOUTBULK_ADDR, /* addr */ - CDCACM_EPOUTBULK_ATTR, /* attr */ - { - LSBYTE(CONFIG_CDCACM_EPBULKOUT_FSSIZE), /* maxpacket (full speed) */ - MSBYTE(CONFIG_CDCACM_EPBULKOUT_FSSIZE) - }, - 1 /* interval */ -}; - -/* Bulk IN endpoint descriptor */ - -static const struct usb_epdesc_s g_epbulkindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - CDCACM_EPINBULK_ADDR, /* addr */ - CDCACM_EPINBULK_ATTR, /* attr */ - { - LSBYTE(CONFIG_CDCACM_EPBULKIN_FSSIZE), /* maxpacket (full speed) */ - MSBYTE(CONFIG_CDCACM_EPBULKIN_FSSIZE) - }, - 1 /* interval */ -}; - -/* The components of the the configuration descriptor are maintained as - * a collection of separate descriptor structure coordinated by the - * following array. These descriptors could have been combined into - * one larger "super" configuration descriptor structure. However, I - * have concerns about compiler-dependent alignment and packing. Since - * the individual structures consist only of byte types, alignment and - * packing is not an issue. And since the are concatentated at run time - * instead of compile time, there should no issues there either. - */ - -static const struct cfgdecsc_group_s g_cfggroup[CDCACM_CFGGROUP_SIZE] = -{ - /* Configuration Descriptor. If the serial device is used in as part - * or a composite device, then the configuration descriptor is - * provided by the composite device logic. - */ - -#if !defined(CONFIG_CDCACM_COMPOSITE) - { - USB_SIZEOF_CFGDESC, /* 1. Configuration descriptor */ - 0, - (FAR void *)&g_cfgdesc - }, - - /* If the serial device is part of a composite device, then it should - * begin with an interface association descriptor (IAD) because the - * CDC/ACM device consists of more than one interface. The IAD associates - * the two CDC/ACM interfaces with the same CDC/ACM device. - */ - -#elif defined(CONFIG_COMPOSITE_IAD) - { - USB_SIZEOF_IADDESC, /* 1. Interface association descriptor */ - 0, - (FAR void *)&g_iaddesc - }, -#endif - { - USB_SIZEOF_IFDESC, /* 2. Notification interface */ - 0, - (FAR void *)&g_notifdesc - }, - { - SIZEOF_HDR_FUNCDESC, /* 3. Header functional descriptor */ - 0, - (FAR void *)&g_funchdr - }, - { - SIZEOF_ACM_FUNCDESC, /* 4. ACM functional descriptor */ - 0, - (FAR void *)&g_acmfunc - }, - { - SIZEOF_UNION_FUNCDESC(1), /* 5. Union functional descriptor */ - 0, - (FAR void *)&g_unionfunc - }, - { - USB_SIZEOF_EPDESC, /* 6. Interrupt IN endpoint descriptor */ - CONFIG_CDCACM_EPINTIN_HSSIZE, - (FAR void *)&g_epintindesc - }, - { - USB_SIZEOF_IFDESC, /* 7. Data interface descriptor */ - 0, - (FAR void *)&g_dataifdesc - }, - { - USB_SIZEOF_EPDESC, /* 8. Bulk OUT endpoint descriptor */ - CONFIG_CDCACM_EPBULKOUT_HSSIZE, - (FAR void *)&g_epbulkoutdesc - }, - { - USB_SIZEOF_EPDESC, /* 9. Bulk OUT endpoint descriptor */ - CONFIG_CDCACM_EPBULKIN_HSSIZE, - (FAR void *)&g_epbulkindesc - } -}; - -#if !defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) -static const struct usb_qualdesc_s g_qualdesc = -{ - USB_SIZEOF_QUALDESC, /* len */ - USB_DESC_TYPE_DEVICEQUALIFIER, /* type */ - { /* usb */ - LSBYTE(0x0200), - MSBYTE(0x0200) - }, - USB_CLASS_VENDOR_SPEC, /* class */ - 0, /* subclass */ - 0, /* protocol */ - CONFIG_CDCACM_EP0MAXPACKET, /* mxpacketsize */ - CDCACM_NCONFIGS, /* nconfigs */ - 0, /* reserved */ -}; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: cdcacm_mkstrdesc - * - * Description: - * Construct a string descriptor - * - ****************************************************************************/ - -int cdcacm_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc) -{ -#if !defined(CONFIG_CDCACM_COMPOSITE) || defined(CONFIG_CDCACM_NOTIFSTR) || \ - defined(CONFIG_CDCACM_DATAIFSTR) - - const char *str; - int len; - int ndata; - int i; - - switch (id) - { -#ifndef CONFIG_CDCACM_COMPOSITE - case 0: - { - /* Descriptor 0 is the language id */ - - strdesc->len = 4; - strdesc->type = USB_DESC_TYPE_STRING; - strdesc->data[0] = LSBYTE(CDCACM_STR_LANGUAGE); - strdesc->data[1] = MSBYTE(CDCACM_STR_LANGUAGE); - return 4; - } - - case CDCACM_MANUFACTURERSTRID: - str = CONFIG_CDCACM_VENDORSTR; - break; - - case CDCACM_PRODUCTSTRID: - str = CONFIG_CDCACM_PRODUCTSTR; - break; - - case CDCACM_SERIALSTRID: - str = CONFIG_CDCACM_SERIALSTR; - break; - - case CDCACM_CONFIGSTRID: - str = CONFIG_CDCACM_CONFIGSTR; - break; -#endif - -#ifdef CONFIG_CDCACM_NOTIFSTR - case CDCACM_NOTIFSTRID: - str = CONFIG_CDCACM_NOTIFSTR; - break; -#endif - -#ifdef CONFIG_CDCACM_DATAIFSTR - case CDCACM_DATAIFSTRID: - str = CONFIG_CDCACM_DATAIFSTR; - break; -#endif - - default: - return -EINVAL; - } - - /* The string is utf16-le. The poor man's utf-8 to utf16-le - * conversion below will only handle 7-bit en-us ascii - */ - - len = strlen(str); - for (i = 0, ndata = 0; i < len; i++, ndata += 2) - { - strdesc->data[ndata] = str[i]; - strdesc->data[ndata+1] = 0; - } - - strdesc->len = ndata+2; - strdesc->type = USB_DESC_TYPE_STRING; - return strdesc->len; -#else - return -EINVAL; -#endif -} - -/**************************************************************************** - * Name: cdcacm_getepdesc - * - * Description: - * Return a pointer to the raw device descriptor - * - ****************************************************************************/ - -#ifndef CONFIG_CDCACM_COMPOSITE -FAR const struct usb_devdesc_s *cdcacm_getdevdesc(void) -{ - return &g_devdesc; -} -#endif - -/**************************************************************************** - * Name: cdcacm_getepdesc - * - * Description: - * Return a pointer to the raw endpoint struct (used for configuring - * endpoints) - * - ****************************************************************************/ - -FAR const struct usb_epdesc_s *cdcacm_getepdesc(enum cdcacm_epdesc_e epid) -{ - switch (epid) - { - case CDCACM_EPINTIN: /* Interrupt IN endpoint */ - return &g_epintindesc; - - case CDCACM_EPBULKOUT: /* Bulk OUT endpoint */ - return &g_epbulkoutdesc; - - case CDCACM_EPBULKIN: /* Bulk IN endpoint */ - return &g_epbulkindesc; - - default: - return NULL; - } -} - -/**************************************************************************** - * Name: cdcacm_mkepdesc - * - * Description: - * Construct the endpoint descriptor using the correct max packet size. - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -void cdcacm_mkepdesc(num cdcacm_epdesc_e epid, uint16_t mxpacket, - FAR struct usb_epdesc_s *outdesc) -{ - FAR const struct usb_epdesc_s *indesc; - - /* Copy the "canned" descriptor */ - - indesc = cdcacm_getepdesc(epid) - memcpy(outdesc, indesc, USB_SIZEOF_EPDESC); - - /* Then add the correct max packet size */ - - outdesc->mxpacketsize[0] = LSBYTE(mxpacket); - outdesc->mxpacketsize[1] = MSBYTE(mxpacket); -} -#endif - -/**************************************************************************** - * Name: cdcacm_mkcfgdesc - * - * Description: - * Construct the configuration descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, uint8_t speed, uint8_t type) -#else -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf) -#endif -{ - FAR const struct cfgdecsc_group_s *group; - FAR uint8_t *dest = buf; - int i; - -#ifdef CONFIG_USBDEV_DUALSPEED - bool hispeed = (speed == USB_SPEED_HIGH); - - /* Check for switches between high and full speed */ - - if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG) - { - hispeed = !hispeed; - } -#endif - - /* Copy all of the descriptors in the group */ - - for (i = 0, dest = buf; i < CDCACM_CFGGROUP_SIZE; i++) - { - group = &g_cfggroup[i]; - - /* The "canned" descriptors all have full speed endpoint maxpacket - * sizes. If high speed is selected, we will have to change the - * endpoint maxpacket size. - * - * Is there a alternative high speed maxpacket size in the table? - * If so, that is sufficient proof that the descriptor that we - * just copied is an endpoint descriptor and needs the fixup - */ - -#ifdef CONFIG_USBDEV_DUALSPEED - if (highspeed && group->hsepsize != 0) - { - cdcacm_mkepdesc(group->desc, group->hsepsize, - (FAR struct usb_epdesc_s*)dest); - } - else -#endif - /* Copy the "canned" descriptor with the full speed max packet - * size - */ - - { - memcpy(dest, group->desc, group->descsize); - } - - /* Advance to the destination location for the next descriptor */ - - dest += group->descsize; - } - - return SIZEOF_CDCACM_CFGDESC; -} - -/**************************************************************************** - * Name: cdcacm_getqualdesc - * - * Description: - * Return a pointer to the raw qual descriptor - * - ****************************************************************************/ - -#if !defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) -FAR const struct usb_qualdesc_s *cdcacm_getqualdesc(void) -{ - return &g_qualdesc; -} -#endif diff --git a/nuttx/drivers/usbdev/composite.c b/nuttx/drivers/usbdev/composite.c deleted file mode 100644 index 530d64416..000000000 --- a/nuttx/drivers/usbdev/composite.c +++ /dev/null @@ -1,933 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/composite.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "composite.h" - -#ifdef CONFIG_USBDEV_COMPOSITE - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure describes the internal state of the driver */ - -struct composite_dev_s -{ - FAR struct usbdev_s *usbdev; /* usbdev driver pointer */ - uint8_t config; /* Configuration number */ - FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */ - struct usbdevclass_driver_s *dev1; /* Device 1 class object */ - struct usbdevclass_driver_s *dev2; /* Device 2 class object */ -}; - -/* The internal version of the class driver */ - -struct composite_driver_s -{ - struct usbdevclass_driver_s drvr; - FAR struct composite_dev_s *dev; -}; - -/* This is what is allocated */ - -struct composite_alloc_s -{ - struct composite_dev_s dev; - struct composite_driver_s drvr; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* USB helps ****************************************************************/ - -static void composite_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); -static int composite_classsetup(FAR struct composite_dev_s *priv, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, - size_t outlen); -static struct usbdev_req_s *composite_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len); -static void composite_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/* USB class device ********************************************************/ - -static int composite_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void composite_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static int composite_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, - size_t outlen); -static void composite_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void composite_suspend(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void composite_resume(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); - -/**************************************************************************** - * Private Data - ****************************************************************************/ -/* USB class device *********************************************************/ - -static const struct usbdevclass_driverops_s g_driverops = -{ - composite_bind, /* bind */ - composite_unbind, /* unbind */ - composite_setup, /* setup */ - composite_disconnect, /* disconnect */ - composite_suspend, /* suspend */ - composite_resume, /* resume */ -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -const char g_compvendorstr[] = CONFIG_COMPOSITE_VENDORSTR; -const char g_compproductstr[] = CONFIG_COMPOSITE_PRODUCTSTR; -const char g_compserialstr[] = CONFIG_COMPOSITE_SERIALSTR; - - /**************************************************************************** - * Private Functions - ****************************************************************************/ -/**************************************************************************** - * Helpers - ****************************************************************************/ - -/**************************************************************************** - * Name: composite_ep0incomplete - * - * Description: - * Handle completion of the composite driver's EP0 control operations - * - ****************************************************************************/ - -static void composite_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - /* Just check the result of the transfer */ - - if (req->result || req->xfrd != req->len) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_REQRESULT), (uint16_t)-req->result); - } -} - -/**************************************************************************** - * Name: composite_classsetup - * - * Description: - * Forward a setup command to the appropriate component device - * - ****************************************************************************/ - -static int composite_classsetup(FAR struct composite_dev_s *priv, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, - FAR uint8_t *dataout, size_t outlen) -{ - uint16_t index; - uint8_t interface; - int ret = -EOPNOTSUPP; - - index = GETUINT16(ctrl->index); - interface = (uint8_t)(index & 0xff); - - if (interface >= DEV1_FIRSTINTERFACE && interface < (DEV1_FIRSTINTERFACE + DEV1_NINTERFACES)) - { - ret = CLASS_SETUP(priv->dev1, dev, ctrl, dataout, outlen); - } - else if (interface >= DEV2_FIRSTINTERFACE && interface < (DEV2_FIRSTINTERFACE + DEV2_NINTERFACES)) - { - ret = CLASS_SETUP(priv->dev2, dev, ctrl, dataout, outlen); - } - - return ret; -} - -/**************************************************************************** - * Name: composite_allocreq - * - * Description: - * Allocate a request instance along with its buffer - * - ****************************************************************************/ - -static struct usbdev_req_s *composite_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len) -{ - FAR struct usbdev_req_s *req; - - req = EP_ALLOCREQ(ep); - if (req != NULL) - { - req->len = len; - req->buf = EP_ALLOCBUFFER(ep, len); - if (!req->buf) - { - EP_FREEREQ(ep, req); - req = NULL; - } - } - return req; -} - -/**************************************************************************** - * Name: composite_freereq - * - * Description: - * Free a request instance along with its buffer - * - ****************************************************************************/ - -static void composite_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - if (ep != NULL && req != NULL) - { - if (req->buf != NULL) - { - EP_FREEBUFFER(ep, req->buf); - } - EP_FREEREQ(ep, req); - } -} - -/**************************************************************************** - * USB Class Driver Methods - ****************************************************************************/ - -/**************************************************************************** - * Name: composite_bind - * - * Description: - * Invoked when the driver is bound to a USB device driver - * - ****************************************************************************/ - -static int composite_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct composite_dev_s *priv = ((FAR struct composite_driver_s*)driver)->dev; - int ret; - - usbtrace(TRACE_CLASSBIND, 0); - - /* Bind the structures */ - - priv->usbdev = dev; - - /* Save the reference to our private data structure in EP0 so that it - * can be recovered in ep0 completion events. - */ - - dev->ep0->priv = priv; - - /* Preallocate one control request */ - - priv->ctrlreq = composite_allocreq(dev->ep0, COMPOSITE_CFGDESCSIZE); - if (priv->ctrlreq == NULL) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_ALLOCCTRLREQ), 0); - ret = -ENOMEM; - goto errout; - } - - /* Initialize the pre-allocated control request */ - - priv->ctrlreq->callback = composite_ep0incomplete; - - /* Then bind each of the constituent class drivers */ - - ret = CLASS_BIND(priv->dev1, dev); - if (ret < 0) - { - goto errout; - } - - ret = CLASS_BIND(priv->dev2, dev); - if (ret < 0) - { - goto errout; - } - - /* Report if we are selfpowered */ - -#ifdef CONFIG_USBDEV_SELFPOWERED - DEV_SETSELFPOWERED(dev); -#endif - - /* And pull-up the data line for the soft connect function */ - - DEV_CONNECT(dev); - return OK; - -errout: - composite_unbind(driver, dev); - return ret; -} - -/**************************************************************************** - * Name: composite_unbind - * - * Description: - * Invoked when the driver is unbound from a USB device driver - * - ****************************************************************************/ - -static void composite_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct composite_dev_s *priv; - irqstate_t flags; - - usbtrace(TRACE_CLASSUNBIND, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct composite_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Make sure that we are not already unbound */ - - if (priv != NULL) - { - /* Unbind the constituent class drivers */ - - flags = irqsave(); - CLASS_UNBIND(priv->dev1, dev); - CLASS_UNBIND(priv->dev2, dev); - - /* Free the pre-allocated control request */ - - priv->config = COMPOSITE_CONFIGIDNONE; - if (priv->ctrlreq != NULL) - { - composite_freereq(dev->ep0, priv->ctrlreq); - priv->ctrlreq = NULL; - } - irqrestore(flags); - } -} - -/**************************************************************************** - * Name: composite_setup - * - * Description: - * Invoked for ep0 control requests. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -static int composite_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, - FAR uint8_t *dataout, size_t outlen) -{ - FAR struct composite_dev_s *priv; - FAR struct usbdev_req_s *ctrlreq; - uint16_t value; - uint16_t index; - uint16_t len; - bool dispatched = false; - int ret = -EOPNOTSUPP; - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0 || !ctrl) - { - usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_SETUPINVALIDARGS), 0); - return -EIO; - } -#endif - - /* Extract a reference to private data */ - - usbtrace(TRACE_CLASSSETUP, ctrl->req); - priv = ((FAR struct composite_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_EP0NOTBOUND2), 0); - return -ENODEV; - } -#endif - ctrlreq = priv->ctrlreq; - - /* Extract the little-endian 16-bit values to host order */ - - value = GETUINT16(ctrl->value); - index = GETUINT16(ctrl->index); - len = GETUINT16(ctrl->len); - - uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", - ctrl->type, ctrl->req, value, index, len); - - if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) - { - /********************************************************************** - * Standard Requests - **********************************************************************/ - - switch (ctrl->req) - { - case USB_REQ_GETDESCRIPTOR: - { - /* The value field specifies the descriptor type in the MS byte and the - * descriptor index in the LS byte (order is little endian) - */ - - switch (ctrl->value[1]) - { - case USB_DESC_TYPE_DEVICE: - { - ret = USB_SIZEOF_DEVDESC; - memcpy(ctrlreq->buf, composite_getdevdesc(), ret); - } - break; - -#ifdef CONFIG_USBDEV_DUALSPEED - case USB_DESC_TYPE_DEVICEQUALIFIER: - { - ret = USB_SIZEOF_QUALDESC; - memcpy(ctrlreq->buf, composite_getqualdesc(), ret); - } - break; - - case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif - - case USB_DESC_TYPE_CONFIG: - { -#ifdef CONFIG_USBDEV_DUALSPEED - ret = composite_mkcfgdesc(ctrlreq->buf, dev->speed, - ctrl->value[1]); -#else - ret = composite_mkcfgdesc(ctrlreq->buf); -#endif - } - break; - - case USB_DESC_TYPE_STRING: - { - /* value == string index. Zero is the language ID. */ - - uint8_t strid = ctrl->value[0]; - FAR struct usb_strdesc_s *buf = (FAR struct usb_strdesc_s *)ctrlreq->buf; - - if (strid <= COMPOSITE_NSTRIDS) - { - ret = composite_mkstrdesc(strid, buf); - } -#if DEV1_NSTRIDS > 0 - else if (strid <= DEV1_STRIDBASE + DEV1_NSTRIDS) - { - ret = DEV1_MKSTRDESC(strid, buf); - } -#endif -#if DEV2_NSTRIDS > 0 - else if (strid <= DEV2_STRIDBASE + DEV2_NSTRIDS) - { - ret = DEV2_MKSTRDESC(strid, buf); - } -#endif - } - break; - - default: - { - usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_GETUNKNOWNDESC), value); - } - break; - } - } - break; - - case USB_REQ_SETCONFIGURATION: - { - if (ctrl->type == 0) - { - /* Save the configuration and inform the constituent classes */ - - ret = CLASS_SETUP(priv->dev1, dev, ctrl, dataout, outlen); - dispatched = true; - - if (ret >= 0) - { - ret = CLASS_SETUP(priv->dev2, dev, ctrl, dataout, outlen); - if (ret >= 0) - { - priv->config = value; - } - } - } - } - break; - - case USB_REQ_GETCONFIGURATION: - { - if (ctrl->type == USB_DIR_IN) - { - ctrlreq->buf[0] = priv->config; - ret = 1; - } - } - break; - - case USB_REQ_SETINTERFACE: - { - if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE && - priv->config == COMPOSITE_CONFIGID) - { - ret = composite_classsetup(priv, dev, ctrl, dataout, outlen); - dispatched = true; - } - } - break; - - case USB_REQ_GETINTERFACE: - { - if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) && - priv->config == COMPOSITE_CONFIGIDNONE) - { - ret = composite_classsetup(priv, dev, ctrl, dataout, outlen); - dispatched = true; - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); - break; - } - } - else - { - uint8_t recipient; - - /********************************************************************** - * Non-Standard Class Requests - **********************************************************************/ - - /* Class implementations should handle there own interface and endpoint - * requests. - */ - - recipient = ctrl->type & USB_REQ_RECIPIENT_MASK; - if (recipient == USB_REQ_RECIPIENT_INTERFACE || recipient == USB_REQ_RECIPIENT_ENDPOINT) - { - ret = composite_classsetup(priv, dev, ctrl, dataout, outlen); - dispatched = true; - } - } - - - /* Respond to the setup command if (1) data was returned, and (2) the request was - * NOT successfully dispatched to the component class driver. On an error return - * value (ret < 0), the USB driver will stall EP0. - */ - - if (ret >= 0 && !dispatched) - { - /* Setup the request */ - - ctrlreq->len = MIN(len, ret); - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - - /* And submit the request to the USB controller driver */ - - ret = EP_SUBMIT(dev->ep0, ctrlreq); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_EPRESPQ), (uint16_t)-ret); - ctrlreq->result = OK; - composite_ep0incomplete(dev->ep0, ctrlreq); - } - } - - return ret; -} - -/**************************************************************************** - * Name: composite_disconnect - * - * Description: - * Invoked after all transfers have been stopped, when the host is - * disconnected. This function is probably called from the context of an - * interrupt handler. - * - ****************************************************************************/ - -static void composite_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct composite_dev_s *priv; - irqstate_t flags; - - usbtrace(TRACE_CLASSDISCONNECT, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct composite_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Reset the configuration and inform the constituent class drivers of - * the disconnection. - */ - - flags = irqsave(); - priv->config = COMPOSITE_CONFIGIDNONE; - CLASS_DISCONNECT(priv->dev1, dev); - CLASS_DISCONNECT(priv->dev2, dev); - irqrestore(flags); - - /* Perform the soft connect function so that we will we can be - * re-enumerated. - */ - - DEV_CONNECT(dev); -} - -/**************************************************************************** - * Name: composite_suspend - * - * Description: - * Invoked on a USB suspend event. - * - ****************************************************************************/ - -static void composite_suspend(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct composite_dev_s *priv; - irqstate_t flags; - - usbtrace(TRACE_CLASSSUSPEND, 0); - -#ifdef CONFIG_DEBUG - if (!dev) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct composite_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Forward the suspend event to the constituent devices */ - - flags = irqsave(); - CLASS_SUSPEND(priv->dev1, priv->usbdev); - CLASS_SUSPEND(priv->dev2, priv->usbdev); - irqrestore(flags); -} - -/**************************************************************************** - * Name: composite_resume - * - * Description: - * Invoked on a USB resume event. - * - ****************************************************************************/ - -static void composite_resume(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct composite_dev_s *priv = NULL; - irqstate_t flags; - -#ifdef CONFIG_DEBUG - if (!dev) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct composite_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Forward the resume event to the constituent devices */ - - flags = irqsave(); - CLASS_RESUME(priv->dev1, priv->usbdev); - CLASS_RESUME(priv->dev2, priv->usbdev); - irqrestore(flags); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ -/**************************************************************************** - * Name: composite_initialize - * - * Description: - * Register USB composite device as configured. This function will call - * board-specific implementations in order to obtain the class objects for - * each of the members of the composite (see board_mscclassobject(), - * board_cdcclassobjec(), ...) - * - * Input Parameter: - * None - * - * Returned Value: - * A non-NULL "handle" is returned on success. This handle may be used - * later with composite_uninitialize() in order to removed the composite - * device. This handle is the (untyped) internal representation of the - * the class driver instance. - * - * NULL is returned on any failure. - * - ****************************************************************************/ - -FAR void *composite_initialize(void) -{ - FAR struct composite_alloc_s *alloc; - FAR struct composite_dev_s *priv; - FAR struct composite_driver_s *drvr; - int ret; - - /* Allocate the structures needed */ - - alloc = (FAR struct composite_alloc_s*)kmalloc(sizeof(struct composite_alloc_s)); - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_ALLOCDEVSTRUCT), 0); - return NULL; - } - - /* Convenience pointers into the allocated blob */ - - priv = &alloc->dev; - drvr = &alloc->drvr; - - /* Initialize the USB composite driver structure */ - - memset(priv, 0, sizeof(struct composite_dev_s)); - - /* Get the constitueat class driver objects */ - - ret = DEV1_CLASSOBJECT(&priv->dev1); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_CLASSOBJECT), (uint16_t)-ret); - goto errout_with_alloc; - } - - ret = DEV2_CLASSOBJECT(&priv->dev2); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_CLASSOBJECT), (uint16_t)-ret); - goto errout_with_alloc; - } - - /* Initialize the USB class driver structure */ - -#ifdef CONFIG_USBDEV_DUALSPEED - drvr->drvr.speed = USB_SPEED_HIGH; -#else - drvr->drvr.speed = USB_SPEED_FULL; -#endif - drvr->drvr.ops = &g_driverops; - drvr->dev = priv; - - /* Register the USB composite class driver */ - - ret = usbdev_register(&drvr->drvr); - if (ret) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_DEVREGISTER), (uint16_t)-ret); - goto errout_with_alloc; - } - - return (FAR void *)alloc; - -errout_with_alloc: - kfree(alloc); - return NULL; -} - -/**************************************************************************** - * Name: composite_uninitialize - * - * Description: - * Un-initialize the USB composite driver. The handle is the USB composite - * class' device object as was returned by composite_initialize(). This - * function will call board-specific implementations in order to free the - * class objects for each of the members of the composite (see - * board_mscuninitialize(), board_cdcuninitialize(), ...) - * - * Input Parameters: - * handle - The handle returned by a previous call to composite_initialize(). - * - * Returned Value: - * None - * - ***************************************************************************/ - -void composite_uninitialize(FAR void *handle) -{ - FAR struct composite_alloc_s *alloc = (FAR struct composite_alloc_s *)handle; - FAR struct composite_dev_s *priv; - - DEBUGASSERT(alloc != NULL); - - /* Uninitialize each of the member classes */ - - priv = &alloc->dev; - if (priv->dev1) - { - DEV1_UNINITIALIZE(priv->dev1); - priv->dev1 = NULL; - } - - if (priv->dev2) - { - DEV1_UNINITIALIZE(priv->dev2); - priv->dev2 = NULL; - } - - /* Then unregister and destroy the composite class */ - - usbdev_unregister(&alloc->drvr.drvr); - - /* Free any resources used by the composite driver */ - /* None */ - - /* Then free the composite driver state structure itself */ - - kfree(priv); -} - -/**************************************************************************** - * Name: composite_ep0submit - * - * Description: - * Members of the composite cannot send on EP0 directly because EP0 is - * is "owned" by the composite device. Instead, when configured as members - * of a composite device, those classes should call this method so that - * the composite device can send on EP0 onbehalf of the class. - * - ****************************************************************************/ - -int composite_ep0submit(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR struct usbdev_req_s *ctrlreq) -{ - /* This function is not really necessary in the current design. However, - * keeping this will provide us a little flexibility in the future if - * it becomes necessary to manage the completion callbacks. - */ - - return EP_SUBMIT(dev->ep0, ctrlreq); -} - -#endif /* CONFIG_USBDEV_COMPOSITE */ diff --git a/nuttx/drivers/usbdev/composite.h b/nuttx/drivers/usbdev/composite.h deleted file mode 100644 index 0c022427c..000000000 --- a/nuttx/drivers/usbdev/composite.h +++ /dev/null @@ -1,326 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/composite.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_USBDEV_COMPOSITE_H -#define __DRIVERS_USBDEV_COMPOSITE_H 1 - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include -#include - -#ifdef CONFIG_USBDEV_COMPOSITE - -#ifdef CONFIG_CDCACM_COMPOSITE -# include -# include "cdcacm.h" -#endif - -#ifdef CONFIG_USBMSC_COMPOSITE -# include "usbmsc.h" -#endif - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* Packet sizes */ - -#ifndef CONFIG_COMPOSITE_EP0MAXPACKET -# define CONFIG_COMPOSITE_EP0MAXPACKET 64 -#endif - -/* Vendor and product IDs and strings */ - -#ifndef CONFIG_COMPOSITE_COMPOSITE -# ifndef CONFIG_COMPOSITE_VENDORID -# warning "CONFIG_COMPOSITE_VENDORID not defined" -# define CONFIG_COMPOSITE_VENDORID 0x03eb -# endif - -# ifndef CONFIG_COMPOSITE_PRODUCTID -# warning "CONFIG_COMPOSITE_PRODUCTID not defined" -# define CONFIG_COMPOSITE_PRODUCTID 0x2022 -# endif - -# ifndef CONFIG_COMPOSITE_VERSIONNO -# define CONFIG_COMPOSITE_VERSIONNO (0x0101) -# endif - -# ifndef CONFIG_COMPOSITE_VENDORSTR -# warning "No Vendor string specified" -# define CONFIG_COMPOSITE_VENDORSTR "NuttX" -# endif - -# ifndef CONFIG_COMPOSITE_PRODUCTSTR -# warning "No Product string specified" -# define CONFIG_COMPOSITE_PRODUCTSTR "Composite Device" -# endif - -# undef CONFIG_COMPOSITE_SERIALSTR -# define CONFIG_COMPOSITE_SERIALSTR "0101" -#endif - -#undef CONFIG_COMPOSITE_CONFIGSTR -#define CONFIG_COMPOSITE_CONFIGSTR "Composite" - -/* Constituent devices ******************************************************/ - -#undef DEV1_IS_CDCACM -#undef DEV1_IS_USBMSC - -#undef DEV2_IS_CDCACM -#undef DEV2_IS_USBMSC - -/* Pick the first device in the composite. At present, this may only be - * the CDC serial device or the mass storage device. - */ - -#if defined(CONFIG_CDCACM_COMPOSITE) -# define DEV1_IS_CDCACM 1 -# define DEV1_MKCFGDESC cdcacm_mkcfgdesc -# define DEV1_MKSTRDESC cdcacm_mkstrdesc -# define DEV1_CLASSOBJECT board_cdcclassobject -# define DEV1_UNINITIALIZE board_cdcuninitialize -# define DEV1_NCONFIGS CDCACM_NCONFIGS -# define DEV1_CONFIGID CDCACM_CONFIGID -# define DEV1_FIRSTINTERFACE CONFIG_CDCACM_IFNOBASE -# define DEV1_NINTERFACES CDCACM_NINTERFACES -# define DEV1_STRIDBASE CONFIG_CDCACM_STRBASE -# define DEV1_NSTRIDS CDCACM_NSTRIDS -# define DEV1_CFGDESCSIZE SIZEOF_CDCACM_CFGDESC -#elif defined(CONFIG_CDCACM_COMPOSITE) -# define DEV1_IS_USBMSC 1 -# define DEV1_MKCFGDESC usbmsc_mkcfgdesc -# define DEV1_MKSTRDESC usbmsc_mkstrdesc -# define DEV1_CLASSOBJECT board_mscclassobject -# define DEV1_UNINITIALIZE board_mscuninitialize -# define DEV1_NCONFIGS USBMSC_NCONFIGS -# define DEV1_CONFIGID USBMSC_CONFIGID -# define DEV1_FIRSTINTERFACE CONFIG_USBMSC_IFNOBASE -# define DEV1_NINTERFACES USBMSC_NINTERFACES -# define DEV1_STRIDBASE CONFIG_USBMSC_IFNOBASE -# define DEV1_NSTRIDS USBMSC_NSTRIDS -# define DEV1_CFGDESCSIZE SIZEOF_USBMSC_CFGDESC -#else -# error "No members of the composite defined" -#endif - -/* Pick the second device in the composite. At present, this may only be - * the CDC serial device or the mass storage device. - */ - -#if defined(CONFIG_CDCACM_COMPOSITE) && !defined(DEV1_IS_CDCACM) -# define DEV2_IS_CDCACM 1 -# define DEV2_MKCFGDESC cdcacm_mkcfgdesc -# define DEV2_MKSTRDESC cdcacm_mkstrdesc -# define DEV2_CLASSOBJECT board_cdcclassobject -# define DEV2_UNINITIALIZE board_cdcuninitialize -# define DEV2_NCONFIGS CDCACM_NCONFIGS -# define DEV2_CONFIGID CDCACM_CONFIGID -# define DEV2_FIRSTINTERFACE CONFIG_CDCACM_IFNOBASE -# define DEV2_NINTERFACES CDCACM_NINTERFACES -# define DEV2_STRIDBASE CONFIG_CDCACM_STRBASE -# define DEV2_NSTRIDS CDCACM_NSTRIDS -# define DEV2_CFGDESCSIZE SIZEOF_CDCACM_CFGDESC -#elif defined(CONFIG_CDCACM_COMPOSITE) && !defined(DEV1_IS_USBMSC) -# define DEV2_IS_USBMSC 1 -# define DEV2_MKCFGDESC usbmsc_mkcfgdesc -# define DEV2_MKSTRDESC usbmsc_mkstrdesc -# define DEV2_UNINITIALIZE board_mscuninitialize -# define DEV2_CLASSOBJECT board_mscclassobject -# define DEV2_NCONFIGS USBMSC_NCONFIGS -# define DEV2_CONFIGID USBMSC_CONFIGID -# define DEV2_FIRSTINTERFACE CONFIG_USBMSC_IFNOBASE -# define DEV2_NINTERFACES USBMSC_NINTERFACES -# define DEV2_STRIDBASE CONFIG_USBMSC_STRBASE -# define DEV2_NSTRIDS USBMSC_NSTRIDS -# define DEV2_CFGDESCSIZE SIZEOF_USBMSC_CFGDESC -#else -# error "Insufficient members of the composite defined" -#endif - -/* Verify interface configuration */ - -#if DEV1_FIRSTINTERFACE != 0 -# warning "The first interface number should be zero" -#endif - -#if (DEV1_FIRSTINTERFACE + DEV1_NINTERFACES) != DEV2_FIRSTINTERFACE -# warning "Interface numbers are not contiguous" -#endif - -/* Check if an IAD is needed */ - -#ifdef CONFIG_COMPOSITE_IAD -# if DEV1_NINTERFACES == 1 && DEV2_NINTERFACES == 1 -# warning "CONFIG_COMPOSITE_IAD not needed" -# endif -#endif - -#if !defined(CONFIG_COMPOSITE_IAD) && DEV1_NINTERFACES > 1 && DEV2_NINTERFACES > 1 -# warning "CONFIG_COMPOSITE_IAD may be needed" -#endif - -/* Total size of the configuration descriptor: */ - -#define COMPOSITE_CFGDESCSIZE (USB_SIZEOF_CFGDESC + DEV1_CFGDESCSIZE + DEV2_CFGDESCSIZE) - -/* The total number of interfaces */ - -#define COMPOSITE_NINTERFACES (DEV1_NINTERFACES + DEV2_NINTERFACES) - -/* Composite configuration ID value */ - -#if DEV1_NCONFIGS != 1 || DEV1_CONFIGID != 1 -# error "DEV1: Only a single configuration is supported" -#endif - -#if DEV2_NCONFIGS != 1 || DEV2_CONFIGID != 1 -# error "DEV2: Only a single configuration is supported" -#endif - -/* Descriptors **************************************************************/ -/* These settings are not modifiable via the NuttX configuration */ - -#define COMPOSITE_CONFIGIDNONE (0) /* Config ID = 0 means to return to address mode */ -#define COMPOSITE_NCONFIGS (1) /* The number of configurations supported */ -#define COMPOSITE_CONFIGID (1) /* The only supported configuration ID */ - -/* String language */ - -#define COMPOSITE_STR_LANGUAGE (0x0409) /* en-us */ - -/* Descriptor strings */ - -#define COMPOSITE_MANUFACTURERSTRID (1) -#define COMPOSITE_PRODUCTSTRID (2) -#define COMPOSITE_SERIALSTRID (3) -#define COMPOSITE_CONFIGSTRID (4) -#define COMPOSITE_NSTRIDS (4) - -/* Verify string configuration */ - -#if COMPOSITE_NSTRIDS != DEV1_STRIDBASE -# warning "The DEV1 string base should be COMPOSITE_NSTRIDS" -#endif - -#if (DEV1_STRIDBASE + DEV1_NSTRIDS) != DEV2_STRIDBASE -# warning "String IDs are not contiguous" -#endif - -/* Everpresent MIN/MAX macros ***********************************************/ - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef MAX -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -extern const char g_compvendorstr[]; -extern const char g_compproductstr[]; -extern const char g_compserialstr[]; - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Name: composite_mkstrdesc - * - * Description: - * Construct a string descriptor - * - ****************************************************************************/ - -int composite_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc); - -/**************************************************************************** - * Name: composite_getepdesc - * - * Description: - * Return a pointer to the composite device descriptor - * - ****************************************************************************/ - -#ifndef CONFIG_COMPOSITE_COMPOSITE -FAR const struct usb_devdesc_s *composite_getdevdesc(void); -#endif - -/**************************************************************************** - * Name: composite_mkcfgdesc - * - * Description: - * Construct the composite configuration descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -int16_t composite_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type); -#else -int16_t composite_mkcfgdesc(uint8_t *buf); -#endif - -/**************************************************************************** - * Name: composite_getqualdesc - * - * Description: - * Return a pointer to the composite qual descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -FAR const struct usb_qualdesc_s *composite_getqualdesc(void); -#endif - -#endif /* CONFIG_USBDEV_COMPOSITE */ -#endif /* __DRIVERS_USBDEV_COMPOSITE_H */ diff --git a/nuttx/drivers/usbdev/composite_desc.c b/nuttx/drivers/usbdev/composite_desc.c deleted file mode 100644 index 0a0cd4a6a..000000000 --- a/nuttx/drivers/usbdev/composite_desc.c +++ /dev/null @@ -1,291 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/composite_desc.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#include "composite.h" - -#ifdef CONFIG_USBDEV_COMPOSITE - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -typedef int16_t (*mkcfgdesc)(FAR uint8_t *buf, uint8_t speed, uint8_t type); -#else -typedef int16_t (*mkcfgdesc)(FAR uint8_t *buf); -#endif - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ -/* Device Descriptor */ - -static const struct usb_devdesc_s g_devdesc = -{ - USB_SIZEOF_DEVDESC, /* len */ - USB_DESC_TYPE_DEVICE, /* type */ - { /* usb */ - LSBYTE(0x0200), - MSBYTE(0x0200) - }, -#ifdef CONFIG_COMPOSITE_IAD - USB_CLASS_MISC, /* classid */ - 2, /* subclass */ - 1, /* protocol */ -#else - USB_CLASS_PER_INTERFACE, /* classid */ - 0, /* subclass */ - 0, /* protocol */ -#endif - CONFIG_COMPOSITE_EP0MAXPACKET, /* maxpacketsize */ - { - LSBYTE(CONFIG_COMPOSITE_VENDORID), /* vendor */ - MSBYTE(CONFIG_COMPOSITE_VENDORID) - }, - { - LSBYTE(CONFIG_COMPOSITE_PRODUCTID), /* product */ - MSBYTE(CONFIG_COMPOSITE_PRODUCTID) - }, - { - LSBYTE(CONFIG_COMPOSITE_VERSIONNO), /* device */ - MSBYTE(CONFIG_COMPOSITE_VERSIONNO) - }, - COMPOSITE_MANUFACTURERSTRID, /* imfgr */ - COMPOSITE_PRODUCTSTRID, /* iproduct */ - COMPOSITE_SERIALSTRID, /* serno */ - COMPOSITE_NCONFIGS /* nconfigs */ -}; - -/* Configuration descriptor for the composite device */ - -static const struct usb_cfgdesc_s g_cfgdesc = -{ - USB_SIZEOF_CFGDESC, /* len */ - USB_DESC_TYPE_CONFIG, /* type */ - { - LSBYTE(COMPOSITE_CFGDESCSIZE), /* LS totallen */ - MSBYTE(COMPOSITE_CFGDESCSIZE) /* MS totallen */ - }, - COMPOSITE_NINTERFACES, /* ninterfaces */ - COMPOSITE_CONFIGID, /* cfgvalue */ - COMPOSITE_CONFIGSTRID, /* icfg */ - USB_CONFIG_ATTR_ONE|SELFPOWERED|REMOTEWAKEUP, /* attr */ - (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */ -}; - -#ifdef CONFIG_USBDEV_DUALSPEED -static const struct usb_qualdesc_s g_qualdesc = -{ - USB_SIZEOF_QUALDESC, /* len */ - USB_DESC_TYPE_DEVICEQUALIFIER, /* type */ - { /* usb */ - LSBYTE(0x0200), - MSBYTE(0x0200) - }, - USB_CLASS_VENDOR_SPEC, /* classid */ - 0, /* subclass */ - 0, /* protocol */ - CONFIG_COMPOSITE_EP0MAXPACKET, /* mxpacketsize */ - COMPOSITE_NCONFIGS, /* nconfigs */ - 0, /* reserved */ -}; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: composite_mkstrdesc - * - * Description: - * Construct a string descriptor - * - ****************************************************************************/ - -int composite_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc) -{ - const char *str; - int len; - int ndata; - int i; - - switch (id) - { - case 0: - { - /* Descriptor 0 is the language id */ - - strdesc->len = 4; - strdesc->type = USB_DESC_TYPE_STRING; - strdesc->data[0] = LSBYTE(COMPOSITE_STR_LANGUAGE); - strdesc->data[1] = MSBYTE(COMPOSITE_STR_LANGUAGE); - return 4; - } - - case COMPOSITE_MANUFACTURERSTRID: - str = g_compvendorstr; - break; - - case COMPOSITE_PRODUCTSTRID: - str = g_compproductstr; - break; - - case COMPOSITE_SERIALSTRID: - str = g_compserialstr; - break; - - case COMPOSITE_CONFIGSTRID: - str = CONFIG_COMPOSITE_CONFIGSTR; - break; - - default: - return -EINVAL; - } - - /* The string is utf16-le. The poor man's utf-8 to utf16-le - * conversion below will only handle 7-bit en-us ascii - */ - - len = strlen(str); - for (i = 0, ndata = 0; i < len; i++, ndata += 2) - { - strdesc->data[ndata] = str[i]; - strdesc->data[ndata+1] = 0; - } - - strdesc->len = ndata+2; - strdesc->type = USB_DESC_TYPE_STRING; - return strdesc->len; -} - -/**************************************************************************** - * Name: composite_getepdesc - * - * Description: - * Return a pointer to the raw device descriptor - * - ****************************************************************************/ - -FAR const struct usb_devdesc_s *composite_getdevdesc(void) -{ - return &g_devdesc; -} - -/**************************************************************************** - * Name: composite_mkcfgdesc - * - * Description: - * Construct the configuration descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -int16_t composite_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type) -#else -int16_t composite_mkcfgdesc(uint8_t *buf) -#endif -{ - int16_t len; - int16_t total; - - /* Configuration descriptor -- Copy the canned configuration descriptor. */ - - memcpy(buf, &g_cfgdesc, USB_SIZEOF_CFGDESC); - total = USB_SIZEOF_CFGDESC; - buf += USB_SIZEOF_CFGDESC; - - /* Copy DEV1/DEV2 interface descriptors */ - -#ifdef CONFIG_USBDEV_DUALSPEED - len = DEV1_MKCFGDESC(buf, speed, type); - total += len; - buf += len; - total += DEV2_MKCFGDESC(buf, speed, type); -#else - len = DEV1_MKCFGDESC(buf); - total += len; - buf += len; - total += DEV2_MKCFGDESC(buf); -#endif - - DEBUGASSERT(total == COMPOSITE_CFGDESCSIZE); - return total; -} - -/**************************************************************************** - * Name: composite_getqualdesc - * - * Description: - * Return a pointer to the raw qual descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -FAR const struct usb_qualdesc_s *composite_getqualdesc(void) -{ - return &g_qualdesc; -} -#endif - -#endif /* CONFIG_USBDEV_COMPOSITE */ diff --git a/nuttx/drivers/usbdev/pl2303.c b/nuttx/drivers/usbdev/pl2303.c deleted file mode 100644 index 7b07a9cba..000000000 --- a/nuttx/drivers/usbdev/pl2303.c +++ /dev/null @@ -1,2355 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/pl2303.c - * - * Copyright (C) 2008-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * This logic emulates the Prolific PL2303 serial/USB converter - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -/* Number of requests in the write queue */ - -#ifndef CONFIG_PL2303_NWRREQS -# define CONFIG_PL2303_NWRREQS 4 -#endif - -/* Number of requests in the read queue */ - -#ifndef CONFIG_PL2303_NRDREQS -# define CONFIG_PL2303_NRDREQS 4 -#endif - -/* Logical endpoint numbers / max packet sizes */ - -#ifndef CONFIG_PL2303_EPINTIN -# warning "EPINTIN not defined in the configuration" -# define CONFIG_PL2303_EPINTIN 1 -#endif - -#ifndef CONFIG_PL2303_EPBULKOUT -# warning "EPBULKOUT not defined in the configuration" -# define CONFIG_PL2303_EPBULKOUT 2 -#endif - -#ifndef CONFIG_PL2303_EPBULKIN -# warning "EPBULKIN not defined in the configuration" -# define CONFIG_PL2303_EPBULKIN 3 -#endif - -/* Packet and request buffer sizes */ - -#ifndef CONFIG_PL2303_EP0MAXPACKET -# define CONFIG_PL2303_EP0MAXPACKET 64 -#endif - -#undef CONFIG_PL2303_BULKREQLEN - -/* Vendor and product IDs and strings */ - -#ifndef CONFIG_PL2303_VENDORID -# define CONFIG_PL2303_VENDORID 0x067b -#endif - -#ifndef CONFIG_PL2303_PRODUCTID -# define CONFIG_PL2303_PRODUCTID 0x2303 -#endif - -#ifndef CONFIG_PL2303_VENDORSTR -# warning "No Vendor string specified" -# define CONFIG_PL2303_VENDORSTR "NuttX" -#endif - -#ifndef CONFIG_PL2303_PRODUCTSTR -# warning "No Product string specified" -# define CONFIG_PL2303_PRODUCTSTR "USBdev Serial" -#endif - -#undef CONFIG_PL2303_SERIALSTR -#define CONFIG_PL2303_SERIALSTR "0" - -#undef CONFIG_PL2303_CONFIGSTR -#define CONFIG_PL2303_CONFIGSTR "Bulk" - -/* USB Controller */ - -#ifndef CONFIG_USBDEV_SELFPOWERED -# define SELFPOWERED USB_CONFIG_ATTR_SELFPOWER -#else -# define SELFPOWERED (0) -#endif - -#ifndef CONFIG_USBDEV_REMOTEWAKEUP -# define REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP -#else -# define REMOTEWAKEUP (0) -#endif - -#ifndef CONFIG_USBDEV_MAXPOWER -# define CONFIG_USBDEV_MAXPOWER 100 -#endif - -/* Descriptors ****************************************************************/ - -/* These settings are not modifiable via the NuttX configuration */ - -#define PL2303_VERSIONNO (0x0202) /* Device version number */ -#define PL2303_CONFIGIDNONE (0) /* Config ID means to return to address mode */ -#define PL2303_CONFIGID (1) /* The only supported configuration ID */ -#define PL2303_NCONFIGS (1) /* Number of configurations supported */ -#define PL2303_INTERFACEID (0) -#define PL2303_ALTINTERFACEID (0) -#define PL2303_NINTERFACES (1) /* Number of interfaces in the configuration */ -#define PL2303_NENDPOINTS (3) /* Number of endpoints in the interface */ - -/* Endpoint configuration */ - -#define PL2303_EPINTIN_ADDR (USB_DIR_IN|CONFIG_PL2303_EPINTIN) -#define PL2303_EPINTIN_ATTR (USB_EP_ATTR_XFER_INT) -#define PL2303_EPINTIN_MXPACKET (10) - -#define PL2303_EPOUTBULK_ADDR (CONFIG_PL2303_EPBULKOUT) -#define PL2303_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK) - -#define PL2303_EPINBULK_ADDR (USB_DIR_IN|CONFIG_PL2303_EPBULKIN) -#define PL2303_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK) - -/* String language */ - -#define PL2303_STR_LANGUAGE (0x0409) /* en-us */ - -/* Descriptor strings */ - -#define PL2303_MANUFACTURERSTRID (1) -#define PL2303_PRODUCTSTRID (2) -#define PL2303_SERIALSTRID (3) -#define PL2303_CONFIGSTRID (4) - -/* Buffer big enough for any of our descriptors */ - -#define PL2303_MXDESCLEN (64) - -/* Vender specific control requests *******************************************/ - -#define PL2303_CONTROL_TYPE (0x20) -#define PL2303_SETLINEREQUEST (0x20) /* OUT, Recipient interface */ -#define PL2303_GETLINEREQUEST (0x21) /* IN, Recipient interface */ -#define PL2303_SETCONTROLREQUEST (0x22) /* OUT, Recipient interface */ -#define PL2303_BREAKREQUEST (0x23) /* OUT, Recipient interface */ - -/* Vendor read/write */ - -#define PL2303_RWREQUEST_TYPE (0x40) -#define PL2303_RWREQUEST (0x01) /* IN/OUT, Recipient device */ - -/* Misc Macros ****************************************************************/ - -/* min/max macros */ - -#ifndef min -# define min(a,b) ((a)<(b)?(a):(b)) -#endif - -#ifndef max -# define max(a,b) ((a)>(b)?(a):(b)) -#endif - -/* Trace values *************************************************************/ - -#define PL2303_CLASSAPI_SETUP TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SETUP) -#define PL2303_CLASSAPI_SHUTDOWN TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SHUTDOWN) -#define PL2303_CLASSAPI_ATTACH TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_ATTACH) -#define PL2303_CLASSAPI_DETACH TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_DETACH) -#define PL2303_CLASSAPI_IOCTL TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_IOCTL) -#define PL2303_CLASSAPI_RECEIVE TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RECEIVE) -#define PL2303_CLASSAPI_RXINT TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RXINT) -#define PL2303_CLASSAPI_RXAVAILABLE TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RXAVAILABLE) -#define PL2303_CLASSAPI_SEND TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SEND) -#define PL2303_CLASSAPI_TXINT TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXINT) -#define PL2303_CLASSAPI_TXREADY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXREADY) -#define PL2303_CLASSAPI_TXEMPTY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXEMPTY) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Container to support a list of requests */ - -struct pl2303_req_s -{ - FAR struct pl2303_req_s *flink; /* Implements a singly linked list */ - FAR struct usbdev_req_s *req; /* The contained request */ -}; - -/* This structure describes the internal state of the driver */ - -struct pl2303_dev_s -{ - FAR struct uart_dev_s serdev; /* Serial device structure */ - FAR struct usbdev_s *usbdev; /* usbdev driver pointer */ - - uint8_t config; /* Configuration number */ - uint8_t nwrq; /* Number of queue write requests (in reqlist)*/ - uint8_t nrdq; /* Number of queue read requests (in epbulkout) */ - bool rxenabled; /* true: UART RX "interrupts" enabled */ - uint8_t linest[7]; /* Fake line status */ - int16_t rxhead; /* Working head; used when rx int disabled */ - - FAR struct usbdev_ep_s *epintin; /* Interrupt IN endpoint structure */ - FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */ - FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */ - FAR struct usbdev_req_s *ctrlreq; /* Control request */ - struct sq_queue_s reqlist; /* List of write request containers */ - - /* Pre-allocated write request containers. The write requests will - * be linked in a free list (reqlist), and used to send requests to - * EPBULKIN; Read requests will be queued in the EBULKOUT. - */ - - struct pl2303_req_s wrreqs[CONFIG_PL2303_NWRREQS]; - struct pl2303_req_s rdreqs[CONFIG_PL2303_NWRREQS]; - - /* Serial I/O buffers */ - - char rxbuffer[CONFIG_PL2303_RXBUFSIZE]; - char txbuffer[CONFIG_PL2303_TXBUFSIZE]; -}; - -/* The internal version of the class driver */ - -struct pl2303_driver_s -{ - struct usbdevclass_driver_s drvr; - FAR struct pl2303_dev_s *dev; -}; - -/* This is what is allocated */ - -struct pl2303_alloc_s -{ - struct pl2303_dev_s dev; - struct pl2303_driver_s drvr; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Transfer helpers *********************************************************/ - -static uint16_t usbclass_fillrequest(FAR struct pl2303_dev_s *priv, - uint8_t *reqbuf, uint16_t reqlen); -static int usbclass_sndpacket(FAR struct pl2303_dev_s *priv); -static inline int usbclass_recvpacket(FAR struct pl2303_dev_s *priv, - uint8_t *reqbuf, uint16_t reqlen); - -/* Request helpers *********************************************************/ - -static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len); -static void usbclass_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/* Configuration ***********************************************************/ - -static int usbclass_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc); -#ifdef CONFIG_USBDEV_DUALSPEED -static void usbclass_mkepbulkdesc(const struct usb_epdesc_s *indesc, - uint16_t mxpacket, struct usb_epdesc_s *outdesc); -static int16_t usbclass_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type); -#else -static int16_t usbclass_mkcfgdesc(uint8_t *buf); -#endif -static void usbclass_resetconfig(FAR struct pl2303_dev_s *priv); -static int usbclass_setconfig(FAR struct pl2303_dev_s *priv, - uint8_t config); - -/* Completion event handlers ***********************************************/ - -static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); -static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); -static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/* USB class device ********************************************************/ - -static int usbclass_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static int usbclass_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, - size_t outlen); -static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -#ifdef CONFIG_SERIAL_REMOVABLE -static void usbclass_suspend(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void usbclass_resume(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -#endif - -/* Serial port *************************************************************/ - -static int usbser_setup(FAR struct uart_dev_s *dev); -static void usbser_shutdown(FAR struct uart_dev_s *dev); -static int usbser_attach(FAR struct uart_dev_s *dev); -static void usbser_detach(FAR struct uart_dev_s *dev); -static void usbser_rxint(FAR struct uart_dev_s *dev, bool enable); -static void usbser_txint(FAR struct uart_dev_s *dev, bool enable); -static bool usbser_txempty(FAR struct uart_dev_s *dev); - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -/* USB class device ********************************************************/ - -static const struct usbdevclass_driverops_s g_driverops = -{ - usbclass_bind, /* bind */ - usbclass_unbind, /* unbind */ - usbclass_setup, /* setup */ - usbclass_disconnect, /* disconnect */ -#ifdef CONFIG_SERIAL_REMOVABLE - usbclass_suspend, /* suspend */ - usbclass_resume, /* resume */ -#else - NULL, /* suspend */ - NULL, /* resume */ -#endif -}; - -/* Serial port *************************************************************/ - -static const struct uart_ops_s g_uartops = -{ - usbser_setup, /* setup */ - usbser_shutdown, /* shutdown */ - usbser_attach, /* attach */ - usbser_detach, /* detach */ - NULL, /* ioctl */ - NULL, /* receive */ - usbser_rxint, /* rxinit */ - NULL, /* rxavailable */ - NULL, /* send */ - usbser_txint, /* txinit */ - NULL, /* txready */ - usbser_txempty /* txempty */ -}; - -/* USB descriptor templates these will be copied and modified **************/ - -static const struct usb_devdesc_s g_devdesc = -{ - USB_SIZEOF_DEVDESC, /* len */ - USB_DESC_TYPE_DEVICE, /* type */ - {LSBYTE(0x0200), MSBYTE(0x0200)}, /* usb */ - USB_CLASS_PER_INTERFACE, /* classid */ - 0, /* subclass */ - 0, /* protocol */ - CONFIG_PL2303_EP0MAXPACKET, /* maxpacketsize */ - { LSBYTE(CONFIG_PL2303_VENDORID), /* vendor */ - MSBYTE(CONFIG_PL2303_VENDORID) }, - { LSBYTE(CONFIG_PL2303_PRODUCTID), /* product */ - MSBYTE(CONFIG_PL2303_PRODUCTID) }, - { LSBYTE(PL2303_VERSIONNO), /* device */ - MSBYTE(PL2303_VERSIONNO) }, - PL2303_MANUFACTURERSTRID, /* imfgr */ - PL2303_PRODUCTSTRID, /* iproduct */ - PL2303_SERIALSTRID, /* serno */ - PL2303_NCONFIGS /* nconfigs */ -}; - -static const struct usb_cfgdesc_s g_cfgdesc = -{ - USB_SIZEOF_CFGDESC, /* len */ - USB_DESC_TYPE_CONFIG, /* type */ - {0, 0}, /* totallen -- to be provided */ - PL2303_NINTERFACES, /* ninterfaces */ - PL2303_CONFIGID, /* cfgvalue */ - PL2303_CONFIGSTRID, /* icfg */ - USB_CONFIG_ATTR_ONE|SELFPOWERED|REMOTEWAKEUP, /* attr */ - (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */ -}; - -static const struct usb_ifdesc_s g_ifdesc = -{ - USB_SIZEOF_IFDESC, /* len */ - USB_DESC_TYPE_INTERFACE, /* type */ - 0, /* ifno */ - 0, /* alt */ - PL2303_NENDPOINTS, /* neps */ - USB_CLASS_VENDOR_SPEC, /* classid */ - 0, /* subclass */ - 0, /* protocol */ - PL2303_CONFIGSTRID /* iif */ -}; - -static const struct usb_epdesc_s g_epintindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - PL2303_EPINTIN_ADDR, /* addr */ - PL2303_EPINTIN_ATTR, /* attr */ - { LSBYTE(PL2303_EPINTIN_MXPACKET), /* maxpacket */ - MSBYTE(PL2303_EPINTIN_MXPACKET) }, - 1 /* interval */ -}; - -static const struct usb_epdesc_s g_epbulkoutdesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - PL2303_EPOUTBULK_ADDR, /* addr */ - PL2303_EPOUTBULK_ATTR, /* attr */ - { LSBYTE(64), MSBYTE(64) }, /* maxpacket -- might change to 512*/ - 0 /* interval */ -}; - -static const struct usb_epdesc_s g_epbulkindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - PL2303_EPINBULK_ADDR, /* addr */ - PL2303_EPINBULK_ATTR, /* attr */ - { LSBYTE(64), MSBYTE(64) }, /* maxpacket -- might change to 512*/ - 0 /* interval */ -}; - -#ifdef CONFIG_USBDEV_DUALSPEED -static const struct usb_qualdesc_s g_qualdesc = -{ - USB_SIZEOF_QUALDESC, /* len */ - USB_DESC_TYPE_DEVICEQUALIFIER, /* type */ - {LSBYTE(0x0200), MSBYTE(0x0200) }, /* USB */ - USB_CLASS_VENDOR_SPEC, /* classid */ - 0, /* subclass */ - 0, /* protocol */ - CONFIG_PL2303_EP0MAXPACKET, /* mxpacketsize */ - PL2303_NCONFIGS, /* nconfigs */ - 0, /* reserved */ -}; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/************************************************************************************ - * Name: usbclass_fillrequest - * - * Description: - * If there is data to send it is copied to the given buffer. Called either - * to initiate the first write operation, or from the completion interrupt handler - * service consecutive write operations. - * - * NOTE: The USB serial driver does not use the serial drivers uart_xmitchars() - * API. That logic is essentially duplicated here because unlike UART hardware, - * we need to be able to handle writes not byte-by-byte, but packet-by-packet. - * Unfortunately, that decision also exposes some internals of the serial driver - * in the following. - * - ************************************************************************************/ - -static uint16_t usbclass_fillrequest(FAR struct pl2303_dev_s *priv, uint8_t *reqbuf, - uint16_t reqlen) -{ - FAR uart_dev_t *serdev = &priv->serdev; - FAR struct uart_buffer_s *xmit = &serdev->xmit; - irqstate_t flags; - uint16_t nbytes = 0; - - /* Disable interrupts */ - - flags = irqsave(); - - /* Transfer bytes while we have bytes available and there is room in the request */ - - while (xmit->head != xmit->tail && nbytes < reqlen) - { - *reqbuf++ = xmit->buffer[xmit->tail]; - nbytes++; - - /* Increment the tail pointer */ - - if (++(xmit->tail) >= xmit->size) - { - xmit->tail = 0; - } - } - - /* When all of the characters have been sent from the buffer - * disable the "TX interrupt". - */ - - if (xmit->head == xmit->tail) - { - uart_disabletxint(serdev); - } - - /* If any bytes were removed from the buffer, inform any waiters - * there there is space available. - */ - - if (nbytes) - { - uart_datasent(serdev); - } - - irqrestore(flags); - return nbytes; -} - -/************************************************************************************ - * Name: usbclass_sndpacket - * - * Description: - * This function obtains write requests, transfers the TX data into the request, - * and submits the requests to the USB controller. This continues untils either - * (1) there are no further packets available, or (2) thre is not further data - * to send. - * - ************************************************************************************/ - -static int usbclass_sndpacket(FAR struct pl2303_dev_s *priv) -{ - FAR struct usbdev_ep_s *ep; - FAR struct usbdev_req_s *req; - FAR struct pl2303_req_s *reqcontainer; - uint16_t reqlen; - irqstate_t flags; - int len; - int ret = OK; - -#ifdef CONFIG_DEBUG - if (priv == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -ENODEV; - } -#endif - - flags = irqsave(); - - /* Use our IN endpoint for the transfer */ - - ep = priv->epbulkin; - - /* Loop until either (1) we run out or write requests, or (2) usbclass_fillrequest() - * is unable to fill the request with data (i.e., until there is no more data - * to be sent). - */ - - uvdbg("head=%d tail=%d nwrq=%d empty=%d\n", - priv->serdev.xmit.head, priv->serdev.xmit.tail, - priv->nwrq, sq_empty(&priv->reqlist)); - - /* Get the maximum number of bytes that will fit into one bulk IN request */ - -#ifdef CONFIG_PL2303_BULKREQLEN - reqlen = MAX(CONFIG_PL2303_BULKREQLEN, ep->maxpacket); -#else - reqlen = ep->maxpacket; -#endif - - while (!sq_empty(&priv->reqlist)) - { - /* Peek at the request in the container at the head of the list */ - - reqcontainer = (struct pl2303_req_s *)sq_peek(&priv->reqlist); - req = reqcontainer->req; - - /* Fill the request with serial TX data */ - - len = usbclass_fillrequest(priv, req->buf, reqlen); - if (len > 0) - { - /* Remove the empty container from the request list */ - - (void)sq_remfirst(&priv->reqlist); - priv->nwrq--; - - /* Then submit the request to the endpoint */ - - req->len = len; - req->priv = reqcontainer; - req->flags = USBDEV_REQFLAGS_NULLPKT; - ret = EP_SUBMIT(ep, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), (uint16_t)-ret); - break; - } - } - else - { - break; - } - } - - irqrestore(flags); - return ret; -} - -/************************************************************************************ - * Name: usbclass_recvpacket - * - * Description: - * A normal completion event was received by the read completion handler at the - * interrupt level (with interrupts disabled). This function handles the USB packet - * and provides the received data to the uart RX buffer. - * - * Assumptions: - * Called from the USB interrupt handler with interrupts disabled. - * - ************************************************************************************/ - -static inline int usbclass_recvpacket(FAR struct pl2303_dev_s *priv, - uint8_t *reqbuf, uint16_t reqlen) -{ - FAR uart_dev_t *serdev = &priv->serdev; - FAR struct uart_buffer_s *recv = &serdev->recv; - uint16_t currhead; - uint16_t nexthead; - uint16_t nbytes = 0; - - /* Get the next head index. During the time that RX interrupts are disabled, the - * the serial driver will be extracting data from the circular buffer and modifying - * recv.tail. During this time, we should avoid modifying recv.head; Instead we will - * use a shadow copy of the index. When interrupts are restored, the real recv.head - * will be updated with this indes. - */ - - if (priv->rxenabled) - { - currhead = recv->head; - } - else - { - currhead = priv->rxhead; - } - - /* Pre-calculate the head index and check for wrap around. We need to do this - * so that we can determine if the circular buffer will overrun BEFORE we - * overrun the buffer! - */ - - nexthead = currhead + 1; - if (nexthead >= recv->size) - { - nexthead = 0; - } - - /* Then copy data into the RX buffer until either: (1) all of the data has been - * copied, or (2) the RX buffer is full. NOTE: If the RX buffer becomes full, - * then we have overrun the serial driver and data will be lost. - */ - - while (nexthead != recv->tail && nbytes < reqlen) - { - /* Copy one byte to the head of the circular RX buffer */ - - recv->buffer[currhead] = *reqbuf++; - - /* Update counts and indices */ - - currhead = nexthead; - nbytes++; - - /* Increment the head index and check for wrap around */ - - nexthead = currhead + 1; - if (nexthead >= recv->size) - { - nexthead = 0; - } - } - - /* Write back the head pointer using the shadow index if RX "interrupts" - * are disabled. - */ - - if (priv->rxenabled) - { - recv->head = currhead; - } - else - { - priv->rxhead = currhead; - } - - /* If data was added to the incoming serial buffer, then wake up any - * threads is waiting for incoming data. If we are running in an interrupt - * handler, then the serial driver will not run until the interrupt handler - * returns. - */ - - if (priv->rxenabled && nbytes > 0) - { - uart_datareceived(serdev); - } - - /* Return an error if the entire packet could not be transferred */ - - if (nbytes < reqlen) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RXOVERRUN), 0); - return -ENOSPC; - } - return OK; -} - -/**************************************************************************** - * Name: usbclass_allocreq - * - * Description: - * Allocate a request instance along with its buffer - * - ****************************************************************************/ - -static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len) -{ - FAR struct usbdev_req_s *req; - - req = EP_ALLOCREQ(ep); - if (req != NULL) - { - req->len = len; - req->buf = EP_ALLOCBUFFER(ep, len); - if (!req->buf) - { - EP_FREEREQ(ep, req); - req = NULL; - } - } - return req; -} - -/**************************************************************************** - * Name: usbclass_freereq - * - * Description: - * Free a request instance along with its buffer - * - ****************************************************************************/ - -static void usbclass_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - if (ep != NULL && req != NULL) - { - if (req->buf != NULL) - { - EP_FREEBUFFER(ep, req->buf); - } - EP_FREEREQ(ep, req); - } -} - -/**************************************************************************** - * Name: usbclass_mkstrdesc - * - * Description: - * Construct a string descriptor - * - ****************************************************************************/ - -static int usbclass_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc) -{ - const char *str; - int len; - int ndata; - int i; - - switch (id) - { - case 0: - { - /* Descriptor 0 is the language id */ - - strdesc->len = 4; - strdesc->type = USB_DESC_TYPE_STRING; - strdesc->data[0] = LSBYTE(PL2303_STR_LANGUAGE); - strdesc->data[1] = MSBYTE(PL2303_STR_LANGUAGE); - return 4; - } - - case PL2303_MANUFACTURERSTRID: - str = CONFIG_PL2303_VENDORSTR; - break; - - case PL2303_PRODUCTSTRID: - str = CONFIG_PL2303_PRODUCTSTR; - break; - - case PL2303_SERIALSTRID: - str = CONFIG_PL2303_SERIALSTR; - break; - - case PL2303_CONFIGSTRID: - str = CONFIG_PL2303_CONFIGSTR; - break; - - default: - return -EINVAL; - } - - /* The string is utf16-le. The poor man's utf-8 to utf16-le - * conversion below will only handle 7-bit en-us ascii - */ - - len = strlen(str); - for (i = 0, ndata = 0; i < len; i++, ndata += 2) - { - strdesc->data[ndata] = str[i]; - strdesc->data[ndata+1] = 0; - } - - strdesc->len = ndata+2; - strdesc->type = USB_DESC_TYPE_STRING; - return strdesc->len; -} - -/**************************************************************************** - * Name: usbclass_mkepbulkdesc - * - * Description: - * Construct the endpoint descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -static inline void usbclass_mkepbulkdesc(const FAR struct usb_epdesc_s *indesc, - uint16_t mxpacket, - FAR struct usb_epdesc_s *outdesc) -{ - /* Copy the canned descriptor */ - - memcpy(outdesc, indesc, USB_SIZEOF_EPDESC); - - /* Then add the correct max packet size */ - - outdesc->mxpacketsize[0] = LSBYTE(mxpacket); - outdesc->mxpacketsize[1] = MSBYTE(mxpacket); -} -#endif - -/**************************************************************************** - * Name: usbclass_mkcfgdesc - * - * Description: - * Construct the configuration descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -static int16_t usbclass_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type) -#else -static int16_t usbclass_mkcfgdesc(uint8_t *buf) -#endif -{ - FAR struct usb_cfgdesc_s *cfgdesc = (struct usb_cfgdesc_s*)buf; -#ifdef CONFIG_USBDEV_DUALSPEED - bool hispeed = (speed == USB_SPEED_HIGH); - uint16_t bulkmxpacket; -#endif - uint16_t totallen; - - /* This is the total length of the configuration (not necessarily the - * size that we will be sending now. - */ - - totallen = USB_SIZEOF_CFGDESC + USB_SIZEOF_IFDESC + PL2303_NENDPOINTS * USB_SIZEOF_EPDESC; - - /* Configuration descriptor -- Copy the canned descriptor and fill in the - * type (we'll also need to update the size below - */ - - memcpy(cfgdesc, &g_cfgdesc, USB_SIZEOF_CFGDESC); - buf += USB_SIZEOF_CFGDESC; - - /* Copy the canned interface descriptor */ - - memcpy(buf, &g_ifdesc, USB_SIZEOF_IFDESC); - buf += USB_SIZEOF_IFDESC; - - /* Make the three endpoint configurations. First, check for switches - * between high and full speed - */ - -#ifdef CONFIG_USBDEV_DUALSPEED - if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG) - { - hispeed = !hispeed; - } -#endif - - memcpy(buf, &g_epintindesc, USB_SIZEOF_EPDESC); - buf += USB_SIZEOF_EPDESC; - -#ifdef CONFIG_USBDEV_DUALSPEED - if (hispeed) - { - bulkmxpacket = 512; - } - else - { - bulkmxpacket = 64; - } - - usbclass_mkepbulkdesc(&g_epbulkoutdesc, bulkmxpacket, (struct usb_epdesc_s*)buf); - buf += USB_SIZEOF_EPDESC; - usbclass_mkepbulkdesc(&g_epbulkindesc, bulkmxpacket, (struct usb_epdesc_s*)buf); -#else - memcpy(buf, &g_epbulkoutdesc, USB_SIZEOF_EPDESC); - buf += USB_SIZEOF_EPDESC; - memcpy(buf, &g_epbulkindesc, USB_SIZEOF_EPDESC); -#endif - - /* Finally, fill in the total size of the configuration descriptor */ - - cfgdesc->totallen[0] = LSBYTE(totallen); - cfgdesc->totallen[1] = MSBYTE(totallen); - return totallen; -} - -/**************************************************************************** - * Name: usbclass_resetconfig - * - * Description: - * Mark the device as not configured and disable all endpoints. - * - ****************************************************************************/ - -static void usbclass_resetconfig(FAR struct pl2303_dev_s *priv) -{ - /* Are we configured? */ - - if (priv->config != PL2303_CONFIGIDNONE) - { - /* Yes.. but not anymore */ - - priv->config = PL2303_CONFIGIDNONE; - - /* Inform the "upper half" driver that there is no (functional) USB - * connection. - */ - -#ifdef CONFIG_SERIAL_REMOVABLE - uart_connected(&priv->serdev, false); -#endif - - /* Disable endpoints. This should force completion of all pending - * transfers. - */ - - EP_DISABLE(priv->epintin); - EP_DISABLE(priv->epbulkin); - EP_DISABLE(priv->epbulkout); - } -} - -/**************************************************************************** - * Name: usbclass_setconfig - * - * Description: - * Set the device configuration by allocating and configuring endpoints and - * by allocating and queue read and write requests. - * - ****************************************************************************/ - -static int usbclass_setconfig(FAR struct pl2303_dev_s *priv, uint8_t config) -{ - FAR struct usbdev_req_s *req; -#ifdef CONFIG_USBDEV_DUALSPEED - struct usb_epdesc_s epdesc; - uint16_t bulkmxpacket; -#endif - int i; - int ret = 0; - -#if CONFIG_DEBUG - if (priv == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -EIO; - } -#endif - - if (config == priv->config) - { - /* Already configured -- Do nothing */ - - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALREADYCONFIGURED), 0); - return 0; - } - - /* Discard the previous configuration data */ - - usbclass_resetconfig(priv); - - /* Was this a request to simply discard the current configuration? */ - - if (config == PL2303_CONFIGIDNONE) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGNONE), 0); - return 0; - } - - /* We only accept one configuration */ - - if (config != PL2303_CONFIGID) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGIDBAD), 0); - return -EINVAL; - } - - /* Configure the IN interrupt endpoint */ - - ret = EP_CONFIGURE(priv->epintin, &g_epintindesc, false); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINCONFIGFAIL), 0); - goto errout; - } - priv->epintin->priv = priv; - - /* Configure the IN bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - if (priv->usbdev->speed == USB_SPEED_HIGH) - { - bulkmxpacket = 512; - } - else - { - bulkmxpacket = 64; - } - - usbclass_mkepbulkdesc(&g_epbulkindesc, bulkmxpacket, &epdesc); - ret = EP_CONFIGURE(priv->epbulkin, &epdesc, false); -#else - ret = EP_CONFIGURE(priv->epbulkin, &g_epbulkindesc, false); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkin->priv = priv; - - /* Configure the OUT bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - usbclass_mkepbulkdesc(&g_epbulkoutdesc, bulkmxpacket, &epdesc); - ret = EP_CONFIGURE(priv->epbulkout, &epdesc, true); -#else - ret = EP_CONFIGURE(priv->epbulkout, &g_epbulkoutdesc, true); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkout->priv = priv; - - /* Queue read requests in the bulk OUT endpoint */ - - DEBUGASSERT(priv->nrdq == 0); - for (i = 0; i < CONFIG_PL2303_NRDREQS; i++) - { - req = priv->rdreqs[i].req; - req->callback = usbclass_rdcomplete; - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-ret); - goto errout; - } - - priv->nrdq++; - } - - /* We are successfully configured */ - - priv->config = config; - - /* Inform the "upper half" driver that we are "open for business" */ - -#ifdef CONFIG_SERIAL_REMOVABLE - uart_connected(&priv->serdev, true); -#endif - - return OK; - -errout: - usbclass_resetconfig(priv); - return ret; -} - -/**************************************************************************** - * Name: usbclass_ep0incomplete - * - * Description: - * Handle completion of EP0 control operations - * - ****************************************************************************/ - -static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - if (req->result || req->xfrd != req->len) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_REQRESULT), (uint16_t)-req->result); - } -} - -/**************************************************************************** - * Name: usbclass_rdcomplete - * - * Description: - * Handle completion of read request on the bulk OUT endpoint. This - * is handled like the receipt of serial data on the "UART" - * - ****************************************************************************/ - -static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - FAR struct pl2303_dev_s *priv; - irqstate_t flags; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct pl2303_dev_s*)ep->priv; - - /* Process the received data unless this is some unusual condition */ - - flags = irqsave(); - switch (req->result) - { - case 0: /* Normal completion */ - usbtrace(TRACE_CLASSRDCOMPLETE, priv->nrdq); - usbclass_recvpacket(priv, req->buf, req->xfrd); - break; - - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0); - priv->nrdq--; - irqrestore(flags); - return; - - default: /* Some other error occurred */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16_t)-req->result); - break; - }; - - /* Requeue the read request */ - -#ifdef CONFIG_PL2303_BULKREQLEN - req->len = max(CONFIG_PL2303_BULKREQLEN, ep->maxpacket); -#else - req->len = ep->maxpacket; -#endif - - ret = EP_SUBMIT(ep, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-req->result); - } - irqrestore(flags); -} - -/**************************************************************************** - * Name: usbclass_wrcomplete - * - * Description: - * Handle completion of write request. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - FAR struct pl2303_dev_s *priv; - FAR struct pl2303_req_s *reqcontainer; - irqstate_t flags; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req || !req->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract references to our private data */ - - priv = (FAR struct pl2303_dev_s *)ep->priv; - reqcontainer = (FAR struct pl2303_req_s *)req->priv; - - /* Return the write request to the free list */ - - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); - priv->nwrq++; - irqrestore(flags); - - /* Send the next packet unless this was some unusual termination - * condition - */ - - switch (req->result) - { - case OK: /* Normal completion */ - usbtrace(TRACE_CLASSWRCOMPLETE, priv->nwrq); - usbclass_sndpacket(priv); - break; - - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRSHUTDOWN), priv->nwrq); - break; - - default: /* Some other error occurred */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), (uint16_t)-req->result); - break; - } -} - -/**************************************************************************** - * USB Class Driver Methods - ****************************************************************************/ - -/**************************************************************************** - * Name: usbclass_bind - * - * Description: - * Invoked when the driver is bound to a USB device driver - * - ****************************************************************************/ - -static int usbclass_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct pl2303_dev_s *priv = ((FAR struct pl2303_driver_s*)driver)->dev; - FAR struct pl2303_req_s *reqcontainer; - irqstate_t flags; - uint16_t reqlen; - int ret; - int i; - - usbtrace(TRACE_CLASSBIND, 0); - - /* Bind the structures */ - - priv->usbdev = dev; - - /* Save the reference to our private data structure in EP0 so that it - * can be recovered in ep0 completion events (Unless we are part of - * a composite device and, in that case, the composite device owns - * EP0). - */ - - dev->ep0->priv = priv; - - /* Preallocate control request */ - - priv->ctrlreq = usbclass_allocreq(dev->ep0, PL2303_MXDESCLEN); - if (priv->ctrlreq == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCCTRLREQ), 0); - ret = -ENOMEM; - goto errout; - } - priv->ctrlreq->callback = usbclass_ep0incomplete; - - /* Pre-allocate all endpoints... the endpoints will not be functional - * until the SET CONFIGURATION request is processed in usbclass_setconfig. - * This is done here because there may be calls to kmalloc and the SET - * CONFIGURATION processing probably occurrs within interrupt handling - * logic where kmalloc calls will fail. - */ - - /* Pre-allocate the IN interrupt endpoint */ - - priv->epintin = DEV_ALLOCEP(dev, PL2303_EPINTIN_ADDR, true, USB_EP_ATTR_XFER_INT); - if (!priv->epintin) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epintin->priv = priv; - - /* Pre-allocate the IN bulk endpoint */ - - priv->epbulkin = DEV_ALLOCEP(dev, PL2303_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkin) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkin->priv = priv; - - /* Pre-allocate the OUT bulk endpoint */ - - priv->epbulkout = DEV_ALLOCEP(dev, PL2303_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkout) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkout->priv = priv; - - /* Pre-allocate read requests */ - -#ifdef CONFIG_PL2303_BULKREQLEN - reqlen = max(CONFIG_PL2303_BULKREQLEN, priv->epbulkout->maxpacket); -#else - reqlen = priv->epbulkout->maxpacket; -#endif - - for (i = 0; i < CONFIG_PL2303_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - reqcontainer->req = usbclass_allocreq(priv->epbulkout, reqlen); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDALLOCREQ), -ENOMEM); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = usbclass_rdcomplete; - } - - /* Pre-allocate write request containers and put in a free list */ - -#ifdef CONFIG_PL2303_BULKREQLEN - reqlen = max(CONFIG_PL2303_BULKREQLEN, priv->epbulkin->maxpacket); -#else - reqlen = priv->epbulkin->maxpacket; -#endif - - for (i = 0; i < CONFIG_PL2303_NWRREQS; i++) - { - reqcontainer = &priv->wrreqs[i]; - reqcontainer->req = usbclass_allocreq(priv->epbulkin, reqlen); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRALLOCREQ), -ENOMEM); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = usbclass_wrcomplete; - - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); - priv->nwrq++; /* Count of write requests available */ - irqrestore(flags); - } - - /* Report if we are selfpowered */ - -#ifdef CONFIG_USBDEV_SELFPOWERED - DEV_SETSELFPOWERED(dev); -#endif - - /* And pull-up the data line for the soft connect function */ - - DEV_CONNECT(dev); - return OK; - -errout: - usbclass_unbind(driver, dev); - return ret; -} - -/**************************************************************************** - * Name: usbclass_unbind - * - * Description: - * Invoked when the driver is unbound from a USB device driver - * - ****************************************************************************/ - -static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct pl2303_dev_s *priv; - FAR struct pl2303_req_s *reqcontainer; - irqstate_t flags; - int i; - - usbtrace(TRACE_CLASSUNBIND, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct pl2303_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Make sure that we are not already unbound */ - - if (priv != NULL) - { - /* Make sure that the endpoints have been unconfigured. If - * we were terminated gracefully, then the configuration should - * already have been reset. If not, then calling usbclass_resetconfig - * should cause the endpoints to immediately terminate all - * transfers and return the requests to us (with result == -ESHUTDOWN) - */ - - usbclass_resetconfig(priv); - up_mdelay(50); - - /* Free the interrupt IN endpoint */ - - if (priv->epintin) - { - DEV_FREEEP(dev, priv->epintin); - priv->epintin = NULL; - } - - /* Free the bulk IN endpoint */ - - if (priv->epbulkin) - { - DEV_FREEEP(dev, priv->epbulkin); - priv->epbulkin = NULL; - } - - /* Free the pre-allocated control request */ - - if (priv->ctrlreq != NULL) - { - usbclass_freereq(dev->ep0, priv->ctrlreq); - priv->ctrlreq = NULL; - } - - /* Free pre-allocated read requests (which should all have - * been returned to the free list at this time -- we don't check) - */ - - DEBUGASSERT(priv->nrdq == 0); - for (i = 0; i < CONFIG_PL2303_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - if (reqcontainer->req) - { - usbclass_freereq(priv->epbulkout, reqcontainer->req); - reqcontainer->req = NULL; - } - } - - /* Free the bulk OUT endpoint */ - - if (priv->epbulkout) - { - DEV_FREEEP(dev, priv->epbulkout); - priv->epbulkout = NULL; - } - - /* Free write requests that are not in use (which should be all - * of them - */ - - flags = irqsave(); - DEBUGASSERT(priv->nwrq == CONFIG_PL2303_NWRREQS); - while (!sq_empty(&priv->reqlist)) - { - reqcontainer = (struct pl2303_req_s *)sq_remfirst(&priv->reqlist); - if (reqcontainer->req != NULL) - { - usbclass_freereq(priv->epbulkin, reqcontainer->req); - priv->nwrq--; /* Number of write requests queued */ - } - } - DEBUGASSERT(priv->nwrq == 0); - irqrestore(flags); - } - - /* Clear out all data in the circular buffer */ - - priv->serdev.xmit.head = 0; - priv->serdev.xmit.tail = 0; -} - -/**************************************************************************** - * Name: usbclass_setup - * - * Description: - * Invoked for ep0 control requests. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -static int usbclass_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, - FAR uint8_t *dataout, size_t outlen) -{ - FAR struct pl2303_dev_s *priv; - FAR struct usbdev_req_s *ctrlreq; - uint16_t value; - uint16_t index; - uint16_t len; - int ret = -EOPNOTSUPP; - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0 || !ctrl) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -EIO; - } -#endif - - /* Extract reference to private data */ - - usbtrace(TRACE_CLASSSETUP, ctrl->req); - priv = ((FAR struct pl2303_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv || !priv->ctrlreq) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); - return -ENODEV; - } -#endif - ctrlreq = priv->ctrlreq; - - /* Extract the little-endian 16-bit values to host order */ - - value = GETUINT16(ctrl->value); - index = GETUINT16(ctrl->index); - len = GETUINT16(ctrl->len); - - uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", - ctrl->type, ctrl->req, value, index, len); - - switch (ctrl->type & USB_REQ_TYPE_MASK) - { - /*********************************************************************** - * Standard Requests - ***********************************************************************/ - - case USB_REQ_TYPE_STANDARD: - { - switch (ctrl->req) - { - case USB_REQ_GETDESCRIPTOR: - { - /* The value field specifies the descriptor type in the MS byte and the - * descriptor index in the LS byte (order is little endian) - */ - - switch (ctrl->value[1]) - { - case USB_DESC_TYPE_DEVICE: - { - ret = USB_SIZEOF_DEVDESC; - memcpy(ctrlreq->buf, &g_devdesc, ret); - } - break; - -#ifdef CONFIG_USBDEV_DUALSPEED - case USB_DESC_TYPE_DEVICEQUALIFIER: - { - ret = USB_SIZEOF_QUALDESC; - memcpy(ctrlreq->buf, &g_qualdesc, ret); - } - break; - - case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif /* CONFIG_USBDEV_DUALSPEED */ - - case USB_DESC_TYPE_CONFIG: - { -#ifdef CONFIG_USBDEV_DUALSPEED - ret = usbclass_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req); -#else - ret = usbclass_mkcfgdesc(ctrlreq->buf); -#endif - } - break; - - case USB_DESC_TYPE_STRING: - { - /* index == language code. */ - - ret = usbclass_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); - } - break; - - default: - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_GETUNKNOWNDESC), value); - } - break; - } - } - break; - - case USB_REQ_SETCONFIGURATION: - { - if (ctrl->type == 0) - { - ret = usbclass_setconfig(priv, value); - } - } - break; - - case USB_REQ_GETCONFIGURATION: - { - if (ctrl->type == USB_DIR_IN) - { - *(uint8_t*)ctrlreq->buf = priv->config; - ret = 1; - } - } - break; - - case USB_REQ_SETINTERFACE: - { - if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE) - { - if (priv->config == PL2303_CONFIGID && - index == PL2303_INTERFACEID && - value == PL2303_ALTINTERFACEID) - { - usbclass_resetconfig(priv); - usbclass_setconfig(priv, priv->config); - ret = 0; - } - } - } - break; - - case USB_REQ_GETINTERFACE: - { - if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) && - priv->config == PL2303_CONFIGIDNONE) - { - if (index != PL2303_INTERFACEID) - { - ret = -EDOM; - } - else - { - *(uint8_t*) ctrlreq->buf = PL2303_ALTINTERFACEID; - ret = 1; - } - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); - break; - } - } - break; - - /*********************************************************************** - * PL2303 Vendor-Specific Requests - ***********************************************************************/ - - case PL2303_CONTROL_TYPE: - { - if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE) - { - switch (ctrl->req) - { - case PL2303_SETLINEREQUEST: - { - memcpy(priv->linest, ctrlreq->buf, min(len, 7)); - ret = 0; - } - break; - - - case PL2303_GETLINEREQUEST: - { - memcpy(ctrlreq->buf, priv->linest, 7); - ret = 7; - } - break; - - case PL2303_SETCONTROLREQUEST: - case PL2303_BREAKREQUEST: - { - ret = 0; - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); - break; - } - } - } - break; - - case PL2303_RWREQUEST_TYPE: - { - if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) - { - if (ctrl->req == PL2303_RWREQUEST) - { - if ((ctrl->type & USB_DIR_IN) != 0) - { - *(uint32_t*)ctrlreq->buf = 0xdeadbeef; - ret = 4; - } - else - { - ret = 0; - } - } - else - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); - } - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDTYPE), ctrl->type); - break; - } - - /* Respond to the setup command if data was returned. On an error return - * value (ret < 0), the USB driver will stall. - */ - - if (ret >= 0) - { - ctrlreq->len = min(len, ret); - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - ret = EP_SUBMIT(dev->ep0, ctrlreq); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPRESPQ), (uint16_t)-ret); - ctrlreq->result = OK; - usbclass_ep0incomplete(dev->ep0, ctrlreq); - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbclass_disconnect - * - * Description: - * Invoked after all transfers have been stopped, when the host is - * disconnected. This function is probably called from the context of an - * interrupt handler. - * - ****************************************************************************/ - -static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct pl2303_dev_s *priv; - irqstate_t flags; - - usbtrace(TRACE_CLASSDISCONNECT, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct pl2303_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); - return; - } -#endif - - /* Inform the "upper half serial driver that we have lost the USB serial - * connection. - */ - - flags = irqsave(); -#ifdef CONFIG_SERIAL_REMOVABLE - uart_connected(&priv->serdev, false); -#endif - - /* Reset the configuration */ - - usbclass_resetconfig(priv); - - /* Clear out all outgoing data in the circular buffer */ - - priv->serdev.xmit.head = 0; - priv->serdev.xmit.tail = 0; - irqrestore(flags); - - /* Perform the soft connect function so that we will we can be - * re-enumerated. - */ - - DEV_CONNECT(dev); -} - -/**************************************************************************** - * Name: usbclass_suspend - * - * Description: - * Handle the USB suspend event. - * - ****************************************************************************/ - -#ifdef CONFIG_SERIAL_REMOVABLE -static void usbclass_suspend(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct cdcacm_dev_s *priv; - - usbtrace(TRACE_CLASSSUSPEND, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - - /* And let the "upper half" driver now that we are suspended */ - - uart_connected(&priv->serdev, false); -} -#endif - -/**************************************************************************** - * Name: usbclass_resume - * - * Description: - * Handle the USB resume event. - * - ****************************************************************************/ - -#ifdef CONFIG_SERIAL_REMOVABLE -static void usbclass_resume(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct cdcacm_dev_s *priv; - - usbtrace(TRACE_CLASSRESUME, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct cdcacm_driver_s*)driver)->dev; - - /* Are we still configured? */ - - if (priv->config != PL2303_CONFIGIDNONE) - { - /* Yes.. let the "upper half" know that have resumed */ - - uart_connected(&priv->serdev, true); - } -} -#endif - -/**************************************************************************** - * Serial Device Methods - ****************************************************************************/ - -/**************************************************************************** - * Name: usbser_setup - * - * Description: - * This method is called the first time that the serial port is opened. - * - ****************************************************************************/ - -static int usbser_setup(FAR struct uart_dev_s *dev) -{ - FAR struct pl2303_dev_s *priv; - - usbtrace(PL2303_CLASSAPI_SETUP, 0); - - /* Sanity check */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return -EIO; - } -#endif - - /* Extract reference to private data */ - - priv = (FAR struct pl2303_dev_s*)dev->priv; - - /* Check if we have been configured */ - - if (priv->config == PL2303_CONFIGIDNONE) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SETUPNOTCONNECTED), 0); - return -ENOTCONN; - } - - return OK; -} - -/**************************************************************************** - * Name: usbser_shutdown - * - * Description: - * This method is called when the serial port is closed. This operation - * is very simple for the USB serial backend because the serial driver - * has already assured that the TX data has full drained -- it calls - * usbser_txempty() until that function returns true before calling this - * function. - * - ****************************************************************************/ - -static void usbser_shutdown(FAR struct uart_dev_s *dev) -{ - usbtrace(PL2303_CLASSAPI_SHUTDOWN, 0); - - /* Sanity check */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - } -#endif -} - -/**************************************************************************** - * Name: usbser_attach - * - * Description: - * Does not apply to the USB serial class device - * - ****************************************************************************/ - -static int usbser_attach(FAR struct uart_dev_s *dev) -{ - usbtrace(PL2303_CLASSAPI_ATTACH, 0); - return OK; -} - -/**************************************************************************** - * Name: usbser_detach - * - * Description: -* Does not apply to the USB serial class device - * - ****************************************************************************/ - -static void usbser_detach(FAR struct uart_dev_s *dev) -{ - usbtrace(PL2303_CLASSAPI_DETACH, 0); -} - -/**************************************************************************** - * Name: usbser_rxint - * - * Description: - * Called by the serial driver to enable or disable RX interrupts. We, of - * course, have no RX interrupts but must behave consistently. This method - * is called under the conditions: - * - * 1. With enable==true when the port is opened (just after usbser_setup - * and usbser_attach are called called) - * 2. With enable==false while transferring data from the RX buffer - * 2. With enable==true while waiting for more incoming data - * 3. With enable==false when the port is closed (just before usbser_detach - * and usbser_shutdown are called). - * - ****************************************************************************/ - -static void usbser_rxint(FAR struct uart_dev_s *dev, bool enable) -{ - FAR struct pl2303_dev_s *priv; - FAR uart_dev_t *serdev; - irqstate_t flags; - - usbtrace(PL2303_CLASSAPI_RXINT, (uint16_t)enable); - - /* Sanity check */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = (FAR struct pl2303_dev_s*)dev->priv; - serdev = &priv->serdev; - - /* We need exclusive access to the RX buffer and private structure - * in the following. - */ - - flags = irqsave(); - if (enable) - { - /* RX "interrupts" are enabled. Is this a transition from disabled - * to enabled state? - */ - - if (!priv->rxenabled) - { - /* Yes. During the time that RX interrupts are disabled, the - * the serial driver will be extracting data from the circular - * buffer and modifying recv.tail. During this time, we - * should avoid modifying recv.head; When interrupts are restored, - * we can update the head pointer for all of the data that we - * put into cicular buffer while "interrupts" were disabled. - */ - - if (priv->rxhead != serdev->recv.head) - { - serdev->recv.head = priv->rxhead; - - /* Yes... signal the availability of new data */ - - uart_datareceived(serdev); - } - - /* RX "interrupts are no longer disabled */ - - priv->rxenabled = true; - } - } - - /* RX "interrupts" are disabled. Is this a transition from enabled - * to disabled state? - */ - - else if (priv->rxenabled) - { - /* Yes. During the time that RX interrupts are disabled, the - * the serial driver will be extracting data from the circular - * buffer and modifying recv.tail. During this time, we - * should avoid modifying recv.head; When interrupts are disabled, - * we use a shadow index and continue adding data to the circular - * buffer. - */ - - priv->rxhead = serdev->recv.head; - priv->rxenabled = false; - } - irqrestore(flags); -} - -/**************************************************************************** - * Name: usbser_txint - * - * Description: - * Called by the serial driver to enable or disable TX interrupts. We, of - * course, have no TX interrupts but must behave consistently. Initially, - * TX interrupts are disabled. This method is called under the conditions: - * - * 1. With enable==false while transferring data into the TX buffer - * 2. With enable==true when data may be taken from the buffer. - * 3. With enable==false when the TX buffer is empty - * - ****************************************************************************/ - -static void usbser_txint(FAR struct uart_dev_s *dev, bool enable) -{ - FAR struct pl2303_dev_s *priv; - - usbtrace(PL2303_CLASSAPI_TXINT, (uint16_t)enable); - - /* Sanity checks */ - -#if CONFIG_DEBUG - if (!dev || !dev->priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct pl2303_dev_s*)dev->priv; - - /* If the new state is enabled and if there is data in the XMIT buffer, - * send the next packet now. - */ - - uvdbg("enable=%d head=%d tail=%d\n", - enable, priv->serdev.xmit.head, priv->serdev.xmit.tail); - - if (enable && priv->serdev.xmit.head != priv->serdev.xmit.tail) - { - usbclass_sndpacket(priv); - } -} - -/**************************************************************************** - * Name: usbser_txempty - * - * Description: - * Return true when all data has been sent. This is called from the - * serial driver when the driver is closed. It will call this API - * periodically until it reports true. NOTE that the serial driver takes all - * responsibility for flushing TX data through the hardware so we can be - * a bit sloppy about that. - * - ****************************************************************************/ - -static bool usbser_txempty(FAR struct uart_dev_s *dev) -{ - FAR struct pl2303_dev_s *priv = (FAR struct pl2303_dev_s*)dev->priv; - - usbtrace(PL2303_CLASSAPI_TXEMPTY, 0); - -#if CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); - return true; - } -#endif - - /* When all of the allocated write requests have been returned to the - * reqlist, then there is no longer any TX data in flight. - */ - - return priv->nwrq >= CONFIG_PL2303_NWRREQS; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbdev_serialinitialize - * - * Description: - * Register USB serial port (and USB serial console if so configured). - * - ****************************************************************************/ - -int usbdev_serialinitialize(int minor) -{ - FAR struct pl2303_alloc_s *alloc; - FAR struct pl2303_dev_s *priv; - FAR struct pl2303_driver_s *drvr; - char devname[16]; - int ret; - - /* Allocate the structures needed */ - - alloc = (FAR struct pl2303_alloc_s*)kmalloc(sizeof(struct pl2303_alloc_s)); - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCDEVSTRUCT), 0); - return -ENOMEM; - } - - /* Convenience pointers into the allocated blob */ - - priv = &alloc->dev; - drvr = &alloc->drvr; - - /* Initialize the USB serial driver structure */ - - memset(priv, 0, sizeof(struct pl2303_dev_s)); - sq_init(&priv->reqlist); - - /* Fake line status */ - - priv->linest[0] = (115200) & 0xff; /* Baud=115200 */ - priv->linest[1] = (115200 >> 8) & 0xff; - priv->linest[2] = (115200 >> 16) & 0xff; - priv->linest[3] = (115200 >> 24) & 0xff; - priv->linest[4] = 0; /* One stop bit */ - priv->linest[5] = 0; /* No parity */ - priv->linest[6] = 8; /*8 data bits */ - - /* Initialize the serial driver sub-structure */ - -#ifdef CONFIG_SERIAL_REMOVABLE - priv->serdev.disconnected = true; -#endif - priv->serdev.recv.size = CONFIG_PL2303_RXBUFSIZE; - priv->serdev.recv.buffer = priv->rxbuffer; - priv->serdev.xmit.size = CONFIG_PL2303_TXBUFSIZE; - priv->serdev.xmit.buffer = priv->txbuffer; - priv->serdev.ops = &g_uartops; - priv->serdev.priv = priv; - - /* Initialize the USB class driver structure */ - -#ifdef CONFIG_USBDEV_DUALSPEED - drvr->drvr.speed = USB_SPEED_HIGH; -#else - drvr->drvr.speed = USB_SPEED_FULL; -#endif - drvr->drvr.ops = &g_driverops; - drvr->dev = priv; - - /* Register the USB serial class driver */ - - ret = usbdev_register(&drvr->drvr); - if (ret) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), (uint16_t)-ret); - goto errout_with_alloc; - } - - /* Register the USB serial console */ - -#ifdef CONFIG_PL2303_CONSOLE - priv->serdev.isconsole = true; - ret = uart_register("/dev/console", &priv->serdev); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONSOLEREGISTER), (uint16_t)-ret); - goto errout_with_class; - } -#endif - - /* Register the single port supported by this implementation */ - - sprintf(devname, "/dev/ttyUSB%d", minor); - ret = uart_register(devname, &priv->serdev); - if (ret) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UARTREGISTER), (uint16_t)-ret); - goto errout_with_class; - } - return OK; - -errout_with_class: - usbdev_unregister(&drvr->drvr); -errout_with_alloc: - kfree(alloc); - return ret; -} diff --git a/nuttx/drivers/usbdev/usbdev_trace.c b/nuttx/drivers/usbdev/usbdev_trace.c deleted file mode 100644 index c332c1358..000000000 --- a/nuttx/drivers/usbdev/usbdev_trace.c +++ /dev/null @@ -1,233 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/usbdev_trace.c - * - * Copyright (C) 2008-2010, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include -#include -#undef usbtrace - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -#ifndef CONFIG_USBDEV_TRACE_NRECORDS -# define CONFIG_USBDEV_TRACE_NRECORDS 128 -#endif - -#ifndef CONFIG_USBDEV_TRACE_INITIALIDSET -# define CONFIG_USBDEV_TRACE_INITIALIDSET 0 -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_TRACE -static struct usbtrace_s g_trace[CONFIG_USBDEV_TRACE_NRECORDS]; -static uint16_t g_head = 0; -static uint16_t g_tail = 0; -#endif - -#if defined(CONFIG_USBDEV_TRACE) || (defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_USB)) -static usbtrace_idset_t g_maskedidset = CONFIG_USBDEV_TRACE_INITIALIDSET; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/******************************************************************************* - * Name: usbtrace_enable - * - * Description: - * Enable/disable tracing per trace ID. The initial state is all IDs enabled. - * - * Input Parameters: - * idset - The bitset of IDs to be masked. TRACE_ALLIDS enables all IDS; zero - * masks all IDs. - * - * Returned Value: - * The previous idset value. - * - * Assumptions: - * - May be called from an interrupt handler - * - *******************************************************************************/ - -#if defined(CONFIG_USBDEV_TRACE) || (defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_USB)) -usbtrace_idset_t usbtrace_enable(usbtrace_idset_t idset) -{ - irqstate_t flags; - usbtrace_idset_t ret; - - /* The following read and write must be atomic */ - - flags = irqsave(); - ret = g_maskedidset; - g_maskedidset = idset; - irqrestore(flags); - return ret; -} -#endif /* CONFIG_USBDEV_TRACE || CONFIG_DEBUG && CONFIG_DEBUG_USB */ - -/******************************************************************************* - * Name: usbtrace - * - * Description: - * Record a USB event (tracing must be enabled) - * - * Assumptions: - * May be called from an interrupt handler - * - *******************************************************************************/ - -#if defined(CONFIG_USBDEV_TRACE) || (defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_USB)) -void usbtrace(uint16_t event, uint16_t value) -{ - irqstate_t flags; - - /* Check if tracing is enabled for this ID */ - - flags = irqsave(); - if ((g_maskedidset & TRACE_ID2BIT(event)) != 0) - { -#ifdef CONFIG_USBDEV_TRACE - /* Yes... save the new trace data at the head */ - - g_trace[g_head].event = event; - g_trace[g_head].value = value; - - /* Increment the head and (probably) the tail index */ - - if (++g_head >= CONFIG_USBDEV_TRACE_NRECORDS) - { - g_head = 0; - } - - if (g_head == g_tail) - { - if (++g_tail >= CONFIG_USBDEV_TRACE_NRECORDS) - { - g_tail = 0; - } - } -#else - /* Just print the data using lowsyslog */ - - usbtrace_trprintf((trprintf_t)lowsyslog, event, value); -#endif - } - irqrestore(flags); -} -#endif /* CONFIG_USBDEV_TRACE || CONFIG_DEBUG && CONFIG_DEBUG_USB */ - -/******************************************************************************* - * Name: usbtrace_enumerate - * - * Description: - * Enumerate all buffer trace data (will temporarily disable tracing) - * - * Assumptions: - * NEVER called from an interrupt handler - * - *******************************************************************************/ - -#ifdef CONFIG_USBDEV_TRACE -int usbtrace_enumerate(trace_callback_t callback, void *arg) -{ - uint16_t ndx; - uint32_t idset; - int ret = OK; - - /* Temporarily disable tracing */ - - idset = usbtrace_enable(0); - - /* Visit every entry, starting with the tail */ - - for (ndx = g_tail; ndx != g_head; ) - { - /* Call the user provided callback */ - - ret = callback(&g_trace[ndx], arg); - if (ret != OK) - { - /* Abort the enumeration */ - - break; - } - - /* Increment the index */ - - if (++ndx >= CONFIG_USBDEV_TRACE_NRECORDS) - { - ndx = 0; - } - } - - /* Discard the trace data after it has been reported */ - - g_tail = g_head; - - /* Restore tracing state */ - - (void)usbtrace_enable(idset); - return ret; -} -#endif /* CONFIG_USBDEV_TRACE */ diff --git a/nuttx/drivers/usbdev/usbdev_trprintf.c b/nuttx/drivers/usbdev/usbdev_trprintf.c deleted file mode 100644 index 2a9921f98..000000000 --- a/nuttx/drivers/usbdev/usbdev_trprintf.c +++ /dev/null @@ -1,253 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/usbdev_trprintf.c - * - * Copyright (C) 2008-2010, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/******************************************************************************* - * Name: usbtrace_trprintf - * - * Description: - * Print the trace record using the supplied printing function - * - *******************************************************************************/ - -void usbtrace_trprintf(trprintf_t trprintf, uint16_t event, uint16_t value) -{ - switch (event) - { - case TRACE_DEVINIT: - trprintf("USB controller initialization: %04x\n", value); - break; - - case TRACE_DEVUNINIT: - trprintf("USB controller un-initialization: %04x\n", value); - break; - - case TRACE_DEVREGISTER: - trprintf("usbdev_register(): %04x\n", value); - break; - - case TRACE_DEVUNREGISTER: - trprintf("usbdev_unregister(): %04x\n", value); - break; - - case TRACE_EPCONFIGURE: - trprintf("Endpoint configure(): %04x\n", value); - break; - - case TRACE_EPDISABLE: - trprintf("Endpoint disable(): %04x\n", value); - break; - - case TRACE_EPALLOCREQ: - trprintf("Endpoint allocreq(): %04x\n", value); - break; - - case TRACE_EPFREEREQ: - trprintf("Endpoint freereq(): %04x\n", value); - break; - - case TRACE_EPALLOCBUFFER: - trprintf("Endpoint allocbuffer(): %04x\n", value); - break; - - case TRACE_EPFREEBUFFER: - trprintf("Endpoint freebuffer(): %04x\n", value); - break; - - case TRACE_EPSUBMIT: - trprintf("Endpoint submit(): %04x\n", value); - break; - - case TRACE_EPCANCEL: - trprintf("Endpoint cancel(): %04x\n", value); - break; - - case TRACE_EPSTALL: - trprintf("Endpoint stall(true): %04x\n", value); - break; - - case TRACE_EPRESUME: - trprintf("Endpoint stall(false): %04x\n", value); - break; - - case TRACE_DEVALLOCEP: - trprintf("Device allocep(): %04x\n", value); - break; - - case TRACE_DEVFREEEP: - trprintf("Device freeep(): %04x\n", value); - break; - - case TRACE_DEVGETFRAME: - trprintf("Device getframe(): %04x\n", value); - break; - - case TRACE_DEVWAKEUP: - trprintf("Device wakeup(): %04x\n", value); - break; - - case TRACE_DEVSELFPOWERED: - trprintf("Device selfpowered(): %04x\n", value); - break; - - case TRACE_DEVPULLUP: - trprintf("Device pullup(): %04x\n", value); - break; - - case TRACE_CLASSBIND: - trprintf("Class bind(): %04x\n", value); - break; - - case TRACE_CLASSUNBIND: - trprintf("Class unbind(): %04x\n", value); - break; - - case TRACE_CLASSDISCONNECT: - trprintf("Class disconnect(): %04x\n", value); - break; - - case TRACE_CLASSSETUP: - trprintf("Class setup(): %04x\n", value); - break; - - case TRACE_CLASSSUSPEND: - trprintf("Class suspend(): %04x\n", value); - break; - - case TRACE_CLASSRESUME: - trprintf("Class resume(): %04x\n", value); - break; - - case TRACE_CLASSRDCOMPLETE: - trprintf("Class RD request complete: %04x\n", value); - break; - - case TRACE_CLASSWRCOMPLETE: - trprintf("Class WR request complete: %04x\n", value); - break; - - default: - switch (TRACE_ID(event)) - { - case TRACE_CLASSAPI_ID: /* Other class driver system API calls */ - trprintf("Class API call %d: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_CLASSSTATE_ID: /* Track class driver state changes */ - trprintf("Class state %d: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_INTENTRY_ID: /* Interrupt handler entry */ - trprintf("Interrupt %d entry: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_INTDECODE_ID: /* Decoded interrupt event */ - trprintf("Interrupt decode %d: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_INTEXIT_ID: /* Interrupt handler exit */ - trprintf("Interrupt %d exit: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_OUTREQQUEUED_ID: /* Request queued for OUT endpoint */ - trprintf("EP%d OUT request queued: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_INREQQUEUED_ID: /* Request queued for IN endpoint */ - trprintf("EP%d IN request queued: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_READ_ID: /* Read (OUT) action */ - trprintf("EP%d OUT read: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_WRITE_ID: /* Write (IN) action */ - trprintf("EP%d IN write: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_COMPLETE_ID: /* Request completed */ - trprintf("EP%d request complete: %04x\n", TRACE_DATA(event), value); - break; - - case TRACE_DEVERROR_ID: /* USB controller driver error event */ - trprintf("Controller error: %02x:%04x\n", TRACE_DATA(event), value); - break; - - case TRACE_CLSERROR_ID: /* USB class driver error event */ - trprintf("Class error: %02x:%04x\n", TRACE_DATA(event), value); - break; - - default: - trprintf("Unrecognized event: %02x:%02x:%04x\n", - TRACE_ID(event) >> 8, TRACE_DATA(event), value); - break; - } - } -} diff --git a/nuttx/drivers/usbdev/usbmsc.c b/nuttx/drivers/usbdev/usbmsc.c deleted file mode 100644 index 68b61814a..000000000 --- a/nuttx/drivers/usbdev/usbmsc.c +++ /dev/null @@ -1,1778 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/usbmsc.c - * - * Copyright (C) 2008-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Mass storage class device. Bulk-only with SCSI subclass. - * - * References: - * "Universal Serial Bus Mass Storage Class, Specification Overview," - * Revision 1.2, USB Implementer's Forum, June 23, 2003. - * - * "Universal Serial Bus Mass Storage Class, Bulk-Only Transport," - * Revision 1.0, USB Implementer's Forum, September 31, 1999. - * - * "SCSI Primary Commands - 3 (SPC-3)," American National Standard - * for Information Technology, May 4, 2005 - * - * "SCSI Primary Commands - 4 (SPC-4)," American National Standard - * for Information Technology, July 19, 2008 - * - * "SCSI Block Commands -2 (SBC-2)," American National Standard - * for Information Technology, November 13, 2004 - * - * "SCSI Multimedia Commands - 3 (MMC-3)," American National Standard - * for Information Technology, November 12, 2001 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "usbmsc.h" - -#ifdef CONFIG_USBMSC_COMPOSITE -# include -# include "composite.h" -#endif - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* The internal version of the class driver */ - -struct usbmsc_driver_s -{ - struct usbdevclass_driver_s drvr; - FAR struct usbmsc_dev_s *dev; -}; - -/* This is what is allocated */ - -struct usbmsc_alloc_s -{ - struct usbmsc_dev_s dev; - struct usbmsc_driver_s drvr; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Class Driver Support *****************************************************/ - -static void usbmsc_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); -static struct usbdev_req_s *usbmsc_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len); -static void usbmsc_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/* Class Driver Operations (most at interrupt level) ************************/ - -static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, - size_t outlen); -static void usbmsc_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); - -/* Initialization/Uninitialization ******************************************/ - -static void usbmsc_lununinitialize(struct usbmsc_lun_s *lun); -#ifdef CONFIG_USBMSC_COMPOSITE -static int usbmsc_exportluns(FAR void *handle); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* Driver operations ********************************************************/ - -static struct usbdevclass_driverops_s g_driverops = -{ - usbmsc_bind, /* bind */ - usbmsc_unbind, /* unbind */ - usbmsc_setup, /* setup */ - usbmsc_disconnect, /* disconnect */ - NULL, /* suspend */ - NULL /* resume */ -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Class Driver Support - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_ep0incomplete - * - * Description: - * Handle completion of EP0 control operations - * - ****************************************************************************/ - -static void usbmsc_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - if (req->result || req->xfrd != req->len) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_REQRESULT), - (uint16_t)-req->result); - } -} - -/**************************************************************************** - * Name: usbmsc_allocreq - * - * Description: - * Allocate a request instance along with its buffer - * - ****************************************************************************/ - -static struct usbdev_req_s *usbmsc_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len) -{ - FAR struct usbdev_req_s *req; - - req = EP_ALLOCREQ(ep); - if (req != NULL) - { - req->len = len; - req->buf = EP_ALLOCBUFFER(ep, len); - if (!req->buf) - { - EP_FREEREQ(ep, req); - req = NULL; - } - } - return req; -} - -/**************************************************************************** - * Name: usbmsc_freereq - * - * Description: - * Free a request instance along with its buffer - * - ****************************************************************************/ - -static void usbmsc_freereq(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req) -{ - if (ep != NULL && req != NULL) - { - if (req->buf != NULL) - { - EP_FREEBUFFER(ep, req->buf); - } - EP_FREEREQ(ep, req); - } -} - -/**************************************************************************** - * Class Driver Interfaces - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_bind - * - * Description: - * Invoked when the driver is bound to a USB device driver - * - ****************************************************************************/ - -static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct usbmsc_dev_s *priv = ((FAR struct usbmsc_driver_s*)driver)->dev; - FAR struct usbmsc_req_s *reqcontainer; - irqstate_t flags; - int ret = OK; - int i; - - usbtrace(TRACE_CLASSBIND, 0); - - /* Bind the structures */ - - priv->usbdev = dev; - - /* Save the reference to our private data structure in EP0 so that it - * can be recovered in ep0 completion events (Unless we are part of - * a composite device and, in that case, the composite device owns - * EP0). - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - dev->ep0->priv = priv; -#endif - - /* The configured EP0 size should match the reported EP0 size. We could - * easily adapt to the reported EP0 size, but then we could not use the - * const, canned descriptors. - */ - - DEBUGASSERT(CONFIG_USBMSC_EP0MAXPACKET == dev->ep0->maxpacket); - - /* Preallocate control request */ - - priv->ctrlreq = usbmsc_allocreq(dev->ep0, USBMSC_MXDESCLEN); - if (priv->ctrlreq == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCCTRLREQ), 0); - ret = -ENOMEM; - goto errout; - } - priv->ctrlreq->callback = usbmsc_ep0incomplete; - - /* Pre-allocate all endpoints... the endpoints will not be functional - * until the SET CONFIGURATION request is processed in usbmsc_setconfig. - * This is done here because there may be calls to kmalloc and the SET - * CONFIGURATION processing probably occurrs within interrupt handling - * logic where kmalloc calls will fail. - */ - - /* Pre-allocate the IN bulk endpoint */ - - priv->epbulkin = DEV_ALLOCEP(dev, USBMSC_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkin) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkin->priv = priv; - - /* Pre-allocate the OUT bulk endpoint */ - - priv->epbulkout = DEV_ALLOCEP(dev, USBMSC_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkout) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKOUTALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkout->priv = priv; - - /* Pre-allocate read requests */ - - for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - reqcontainer->req = usbmsc_allocreq(priv->epbulkout, CONFIG_USBMSC_BULKOUTREQLEN); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDALLOCREQ), - (uint16_t)-ret); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = usbmsc_rdcomplete; - } - - /* Pre-allocate write request containers and put in a free list */ - - for (i = 0; i < CONFIG_USBMSC_NWRREQS; i++) - { - reqcontainer = &priv->wrreqs[i]; - reqcontainer->req = usbmsc_allocreq(priv->epbulkin, CONFIG_USBMSC_BULKINREQLEN); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRALLOCREQ), - (uint16_t)-ret); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = usbmsc_wrcomplete; - - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->wrreqlist); - irqrestore(flags); - } - - /* Report if we are selfpowered (unless we are part of a composite device) */ - -#ifndef CONFIG_USBMSC_COMPOSITE -#ifdef CONFIG_USBDEV_SELFPOWERED - DEV_SETSELFPOWERED(dev); -#endif - - /* And pull-up the data line for the soft connect function (unless we are - * part of a composite device) - */ - - DEV_CONNECT(dev); -#endif - return OK; - -errout: - usbmsc_unbind(driver, dev); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_unbind - * - * Description: - * Invoked when the driver is unbound from a USB device driver - * - ****************************************************************************/ - -static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_req_s *reqcontainer; - irqstate_t flags; - int i; - - usbtrace(TRACE_CLASSUNBIND, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNBINDINVALIDARGS), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct usbmsc_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND1), 0); - return; - } -#endif - - /* The worker thread should have already been stopped by the - * driver un-initialize logic. - */ - - DEBUGASSERT(priv->thstate == USBMSC_STATE_TERMINATED); - - /* Make sure that we are not already unbound */ - - if (priv != NULL) - { - /* Make sure that the endpoints have been unconfigured. If - * we were terminated gracefully, then the configuration should - * already have been reset. If not, then calling usbmsc_resetconfig - * should cause the endpoints to immediately terminate all - * transfers and return the requests to us (with result == -ESHUTDOWN) - */ - - usbmsc_resetconfig(priv); - up_mdelay(50); - - /* Free the pre-allocated control request */ - - if (priv->ctrlreq != NULL) - { - usbmsc_freereq(dev->ep0, priv->ctrlreq); - priv->ctrlreq = NULL; - } - - /* Free pre-allocated read requests (which should all have - * been returned to the free list at this time -- we don't check) - */ - - for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - if (reqcontainer->req) - { - usbmsc_freereq(priv->epbulkout, reqcontainer->req); - reqcontainer->req = NULL; - } - } - - /* Free the bulk OUT endpoint */ - - if (priv->epbulkout) - { - DEV_FREEEP(dev, priv->epbulkout); - priv->epbulkout = NULL; - } - - /* Free write requests that are not in use (which should be all - * of them - */ - - flags = irqsave(); - while (!sq_empty(&priv->wrreqlist)) - { - reqcontainer = (struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); - if (reqcontainer->req != NULL) - { - usbmsc_freereq(priv->epbulkin, reqcontainer->req); - } - } - - /* Free the bulk IN endpoint */ - - if (priv->epbulkin) - { - DEV_FREEEP(dev, priv->epbulkin); - priv->epbulkin = NULL; - } - - irqrestore(flags); - } -} - -/**************************************************************************** - * Name: usbmsc_setup - * - * Description: - * Invoked for ep0 control requests. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, - FAR uint8_t *dataout, size_t outlen) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbdev_req_s *ctrlreq; - uint16_t value; - uint16_t index; - uint16_t len; - int ret = -EOPNOTSUPP; - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0 || !ctrl) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETUPINVALIDARGS), 0); - return -EIO; - } -#endif - - /* Extract reference to private data */ - - usbtrace(TRACE_CLASSSETUP, ctrl->req); - priv = ((FAR struct usbmsc_driver_s *)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv || !priv->ctrlreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND2), 0); - return -ENODEV; - } -#endif - ctrlreq = priv->ctrlreq; - - /* Extract the little-endian 16-bit values to host order */ - - value = GETUINT16(ctrl->value); - index = GETUINT16(ctrl->index); - len = GETUINT16(ctrl->len); - - uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", - ctrl->type, ctrl->req, value, index, len); - - if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) - { - /********************************************************************** - * Standard Requests - **********************************************************************/ - - switch (ctrl->req) - { - case USB_REQ_GETDESCRIPTOR: - { - /* The value field specifies the descriptor type in the MS byte and the - * descriptor index in the LS byte (order is little endian) - */ - - switch (ctrl->value[1]) - { - /* If the mass storage device is used in as part of a composite - * device, then the device descriptor is is provided by logic - * in the composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_DESC_TYPE_DEVICE: - { - ret = USB_SIZEOF_DEVDESC; - memcpy(ctrlreq->buf, usbmsc_getdevdesc(), ret); - } - break; -#endif - - /* If the mass storage device is used in as part of a composite device, - * then the device qualifier descriptor is provided by logic in the - * composite device implementation. - */ - -#if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) - case USB_DESC_TYPE_DEVICEQUALIFIER: - { - ret = USB_SIZEOF_QUALDESC; - memcpy(ctrlreq->buf, usbmsc_getqualdesc(), ret); - } - break; - - case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif - - /* If the mass storage device is used in as part of a composite device, - * then the configuration descriptor is provided by logic in the - * composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_DESC_TYPE_CONFIG: - { -#ifdef CONFIG_USBDEV_DUALSPEED - ret = usbmsc_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->value[1]); -#else - ret = usbmsc_mkcfgdesc(ctrlreq->buf); -#endif - } - break; -#endif - - /* If the mass storage device is used in as part of a composite device, - * then the language string descriptor is provided by logic in the - * composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_DESC_TYPE_STRING: - { - /* index == language code. */ - - ret = usbmsc_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); - } - break; -#endif - - default: - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_GETUNKNOWNDESC), value); - } - break; - } - } - break; - - case USB_REQ_SETCONFIGURATION: - { - if (ctrl->type == 0) - { - /* Signal the worker thread to instantiate the new configuration */ - - priv->theventset |= USBMSC_EVENT_CFGCHANGE; - priv->thvalue = value; - pthread_cond_signal(&priv->cond); - - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; - } - } - break; - - /* If the mass storage device is used in as part of a composite device, - * then the overall composite class configuration is managed by logic - * in the composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_REQ_GETCONFIGURATION: - { - if (ctrl->type == USB_DIR_IN) - { - ctrlreq->buf[0] = priv->config; - ret = 1; - } - } - break; -#endif - - case USB_REQ_SETINTERFACE: - { - if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE) - { - if (priv->config == USBMSC_CONFIGID && - index == USBMSC_INTERFACEID && - value == USBMSC_ALTINTERFACEID) - { - /* Signal to instantiate the interface change */ - - priv->theventset |= USBMSC_EVENT_IFCHANGE; - pthread_cond_signal(&priv->cond); - - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; - } - } - } - break; - - case USB_REQ_GETINTERFACE: - { - if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) && - priv->config == USBMSC_CONFIGIDNONE) - { - if (index != USBMSC_INTERFACEID) - { - ret = -EDOM; - } - else - { - ctrlreq->buf[0] = USBMSC_ALTINTERFACEID; - ret = 1; - } - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); - break; - } - } - else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS) - { - /********************************************************************** - * Bulk-Only Mass Storage Class Requests - **********************************************************************/ - - /* Verify that we are configured */ - - if (!priv->config) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_NOTCONFIGURED), 0); - return ret; - } - - switch (ctrl->req) - { - case USBMSC_REQ_MSRESET: /* Reset mass storage device and interface */ - { - if (ctrl->type == USBMSC_TYPE_SETUPOUT && value == 0 && len == 0) - { - /* Only one interface is supported */ - - if (index != USBMSC_INTERFACEID) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_MSRESETNDX), index); - ret = -EDOM; - } - else - { - /* Signal to stop the current operation and reinitialize state */ - - priv->theventset |= USBMSC_EVENT_RESET; - pthread_cond_signal(&priv->cond); - - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; - } - } - } - break; - - case USBMSC_REQ_GETMAXLUN: /* Return number LUNs supported */ - { - if (ctrl->type == USBMSC_TYPE_SETUPIN && value == 0 && len == 1) - { - /* Only one interface is supported */ - - if (index != USBMSC_INTERFACEID) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_GETMAXLUNNDX), index); - ret = -EDOM; - } - else - { - ctrlreq->buf[0] = priv->nluns - 1; - ret = 1; - } - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BADREQUEST), ctrl->req); - break; - } - } - else - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNSUPPORTEDTYPE), ctrl->type); - } - - /* Respond to the setup command if data was returned. On an error return - * value (ret < 0), the USB driver will stall EP0. - */ - - if (ret >= 0) - { - /* Configure the response */ - - ctrlreq->len = MIN(len, ret); - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - - /* Send the response -- either directly to the USB controller or - * indirectly in the case where this class is a member of a composite - * device. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - ret = EP_SUBMIT(dev->ep0, ctrlreq); -#else - ret = composite_ep0submit(driver, dev, ctrlreq); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPRESPQ), (uint16_t)-ret); -#if 0 /* Not necessary */ - ctrlreq->result = OK; - usbmsc_ep0incomplete(dev->ep0, ctrlreq); -#endif - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbmsc_disconnect - * - * Description: - * Invoked after all transfers have been stopped, when the host is - * disconnected. This function is probably called from the context of an - * interrupt handler. - * - ****************************************************************************/ - -static void usbmsc_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - struct usbmsc_dev_s *priv; - irqstate_t flags; - - usbtrace(TRACE_CLASSDISCONNECT, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DISCONNECTINVALIDARGS), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct usbmsc_driver_s *)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND3), 0); - return; - } -#endif - - /* Reset the configuration */ - - flags = irqsave(); - usbmsc_resetconfig(priv); - - /* Signal the worker thread */ - - priv->theventset |= USBMSC_EVENT_DISCONNECT; - pthread_cond_signal(&priv->cond); - irqrestore(flags); - - /* Perform the soft connect function so that we will we can be - * re-enumerated (unless we are part of a composite device) - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - DEV_CONNECT(dev); -#endif -} - -/**************************************************************************** - * Initialization/Un-Initialization - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_lununinitialize - ****************************************************************************/ - -static void usbmsc_lununinitialize(struct usbmsc_lun_s *lun) -{ - /* Has a block driver has been bound to the LUN? */ - - if (lun->inode) - { - /* Close the block driver */ - - (void)close_blockdriver(lun->inode); - } - - memset(lun, 0, sizeof(struct usbmsc_lun_s *)); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ -/**************************************************************************** - * Internal Interfaces - ****************************************************************************/ - -/**************************************************************************** - * Name: usbmsc_setconfig - * - * Description: - * Set the device configuration by allocating and configuring endpoints and - * by allocating and queuing read and write requests. - * - ****************************************************************************/ - -int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) -{ - FAR struct usbmsc_req_s *privreq; - FAR struct usbdev_req_s *req; -#ifdef CONFIG_USBDEV_DUALSPEED - FAR const struct usb_epdesc_s *epdesc; - bool hispeed = (priv->usbdev->speed == USB_SPEED_HIGH); - uint16_t bulkmxpacket; -#endif - int i; - int ret = 0; - -#if CONFIG_DEBUG - if (priv == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETCONFIGINVALIDARGS), 0); - return -EIO; - } -#endif - - if (config == priv->config) - { - /* Already configured -- Do nothing */ - - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALREADYCONFIGURED), 0); - return OK; - } - - /* Discard the previous configuration data */ - - usbmsc_resetconfig(priv); - - /* Was this a request to simply discard the current configuration? */ - - if (config == USBMSC_CONFIGIDNONE) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CONFIGNONE), 0); - return OK; - } - - /* We only accept one configuration */ - - if (config != USBMSC_CONFIGID) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CONFIGIDBAD), 0); - return -EINVAL; - } - - /* Configure the IN bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - bulkmxpacket = USBMSC_BULKMAXPACKET(hispeed); - epdesc = USBMSC_EPBULKINDESC(hispeed); - ret = EP_CONFIGURE(priv->epbulkin, epdesc, false); -#else - ret = EP_CONFIGURE(priv->epbulkin, - usbmsc_getepdesc(USBMSC_EPFSBULKIN), false); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKINCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkin->priv = priv; - - /* Configure the OUT bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - epdesc = USBMSC_EPBULKOUTDESC(hispeed); - ret = EP_CONFIGURE(priv->epbulkout, epdesc, true); -#else - ret = EP_CONFIGURE(priv->epbulkout, - usbmsc_getepdesc(USBMSC_EPFSBULKOUT), true); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKOUTCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkout->priv = priv; - - /* Queue read requests in the bulk OUT endpoint */ - - for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) - { - privreq = &priv->rdreqs[i]; - req = privreq->req; - req->len = CONFIG_USBMSC_BULKOUTREQLEN; - req->priv = privreq; - req->callback = usbmsc_rdcomplete; - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSUBMIT), (uint16_t)-ret); - goto errout; - } - } - - priv->config = config; - return OK; - -errout: - usbmsc_resetconfig(priv); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_resetconfig - * - * Description: - * Mark the device as not configured and disable all endpoints. - * - ****************************************************************************/ - -void usbmsc_resetconfig(FAR struct usbmsc_dev_s *priv) -{ - /* Are we configured? */ - - if (priv->config != USBMSC_CONFIGIDNONE) - { - /* Yes.. but not anymore */ - - priv->config = USBMSC_CONFIGIDNONE; - - /* Disable endpoints. This should force completion of all pending - * transfers. - */ - - EP_DISABLE(priv->epbulkin); - EP_DISABLE(priv->epbulkout); - } -} - -/**************************************************************************** - * Name: usbmsc_wrcomplete - * - * Description: - * Handle completion of write request. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_req_s *privreq; - irqstate_t flags; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req || !req->priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRCOMPLETEINVALIDARGS), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct usbmsc_dev_s*)ep->priv; - privreq = (FAR struct usbmsc_req_s *)req->priv; - - /* Return the write request to the free list */ - - flags = irqsave(); - sq_addlast((sq_entry_t*)privreq, &priv->wrreqlist); - irqrestore(flags); - - /* Process the received data unless this is some unusual condition */ - - switch (req->result) - { - case OK: /* Normal completion */ - usbtrace(TRACE_CLASSWRCOMPLETE, req->xfrd); - break; - - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRSHUTDOWN), 0); - break; - - default: /* Some other error occurred */ - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRUNEXPECTED), - (uint16_t)-req->result); - break; - }; - - /* Inform the worker thread that a write request has been returned */ - - priv->theventset |= USBMSC_EVENT_WRCOMPLETE; - pthread_cond_signal(&priv->cond); -} - -/**************************************************************************** - * Name: usbmsc_rdcomplete - * - * Description: - * Handle completion of read request on the bulk OUT endpoint. This - * is handled like the receipt of serial data on the "UART" - * - ****************************************************************************/ - -void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_req_s *privreq; - irqstate_t flags; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req || !req->priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETEINVALIDARGS), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct usbmsc_dev_s*)ep->priv; - privreq = (FAR struct usbmsc_req_s *)req->priv; - - /* Process the received data unless this is some unusual condition */ - - switch (req->result) - { - case 0: /* Normal completion */ - { - usbtrace(TRACE_CLASSRDCOMPLETE, req->xfrd); - - /* Add the filled read request from the rdreqlist */ - - flags = irqsave(); - sq_addlast((sq_entry_t*)privreq, &priv->rdreqlist); - irqrestore(flags); - - /* Signal the worker thread that there is received data to be processed */ - - priv->theventset |= USBMSC_EVENT_RDCOMPLETE; - pthread_cond_signal(&priv->cond); - } - break; - - case -ESHUTDOWN: /* Disconnection */ - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSHUTDOWN), 0); - - /* Drop the read request... it will be cleaned up later */ - } - break; - - default: /* Some other error occurred */ - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDUNEXPECTED), - (uint16_t)-req->result); - - /* Return the read request to the bulk out endpoint for re-filling */ - - req = privreq->req; - req->priv = privreq; - req->callback = usbmsc_rdcomplete; - - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETERDSUBMIT), - (uint16_t)-ret); - } - } - break; - } -} - -/**************************************************************************** - * Name: usbmsc_deferredresponse - * - * Description: - * Some EP0 setup request cannot be responded to immediately becuase they - * require some asynchronous action from the SCSI worker thread. This - * function is provided for the SCSI thread to make that deferred response. - * The specific requests that require this deferred response are: - * - * 1. USB_REQ_SETCONFIGURATION, - * 2. USB_REQ_SETINTERFACE, or - * 3. USBMSC_REQ_MSRESET - * - * In all cases, the success reponse is a zero-length packet; the failure - * response is an EP0 stall. - * - * Input parameters: - * priv - Private state structure for this USB storage instance - * stall - true is the action failed and a stall is required - * - ****************************************************************************/ - -void usbmsc_deferredresponse(FAR struct usbmsc_dev_s *priv, bool failed) -{ - FAR struct usbdev_s *dev; - FAR struct usbdev_req_s *ctrlreq; - int ret; - -#ifdef CONFIG_DEBUG - if (!priv || !priv->usbdev || !priv->ctrlreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DEFERREDRESPINVALIDARGS), 0); - return; - } -#endif - - dev = priv->usbdev; - ctrlreq = priv->ctrlreq; - - /* If no error occurs, respond to the deferred setup command with a null - * packet. - */ - - if (!failed) - { - ctrlreq->len = 0; - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - ret = EP_SUBMIT(dev->ep0, ctrlreq); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DEFERREDRESPSUBMIT), - (uint16_t)-ret); -#if 0 /* Not necessary */ - ctrlreq->result = OK; - usbmsc_ep0incomplete(dev->ep0, ctrlreq); -#endif - } - } - else - { - /* On a failure, the USB driver will stall. */ - - usbtrace(TRACE_DEVERROR(USBMSC_TRACEERR_DEFERREDRESPSTALLED), 0); - EP_STALL(dev->ep0); - } -} - -/**************************************************************************** - * User Interfaces - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_configure - * - * Description: - * One-time initialization of the USB storage driver. The initialization - * sequence is as follows: - * - * 1. Call usbmsc_configure to perform one-time initialization specifying - * the number of luns. - * 2. Call usbmsc_bindlun to configure each supported LUN - * 3. Call usbmsc_exportluns when all LUNs are configured - * - * Input Parameters: - * nluns - the number of LUNs that will be registered - * handle - Location to return a handle that is used in other API calls. - * - * Returned Value: - * 0 on success; a negated errno on failure - * - ****************************************************************************/ - -int usbmsc_configure(unsigned int nluns, void **handle) -{ - FAR struct usbmsc_alloc_s *alloc; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_driver_s *drvr; - int ret; - -#ifdef CONFIG_DEBUG - if (nluns > 15) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_TOOMANYLUNS), 0); - return -EDOM; - } -#endif - - /* Allocate the structures needed */ - - alloc = (FAR struct usbmsc_alloc_s*)kmalloc(sizeof(struct usbmsc_alloc_s)); - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCDEVSTRUCT), 0); - return -ENOMEM; - } - - /* Initialize the USB storage driver structure */ - - priv = &alloc->dev; - memset(priv, 0, sizeof(struct usbmsc_dev_s)); - - pthread_mutex_init(&priv->mutex, NULL); - pthread_cond_init(&priv->cond, NULL); - sq_init(&priv->wrreqlist); - - priv->nluns = nluns; - - /* Allocate the LUN table */ - - priv->luntab = (struct usbmsc_lun_s*)kmalloc(priv->nluns*sizeof(struct usbmsc_lun_s)); - if (!priv->luntab) - { - ret = -ENOMEM; - goto errout; - } - memset(priv->luntab, 0, priv->nluns * sizeof(struct usbmsc_lun_s)); - - /* Initialize the USB class driver structure */ - - drvr = &alloc->drvr; -#ifdef CONFIG_USBDEV_DUALSPEED - drvr->drvr.speed = USB_SPEED_HIGH; -#else - drvr->drvr.speed = USB_SPEED_FULL; -#endif - drvr->drvr.ops = &g_driverops; - drvr->dev = priv; - - /* Return the handle and success */ - - *handle = (FAR void*)alloc; - return OK; - -errout: - usbmsc_uninitialize(alloc); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_bindlun - * - * Description: - * Bind the block driver specified by drvrpath to a USB storage LUN. - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * drvrpath - the full path to the block driver - * startsector - A sector offset into the block driver to the start of the - * partition on drvrpath (0 if no partitions) - * nsectors - The number of sectors in the partition (if 0, all sectors - * to the end of the media will be exported). - * lunno - the LUN to bind to - * - * Returned Value: - * 0 on success; a negated errno on failure. - * - ****************************************************************************/ - -int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath, - unsigned int lunno, off_t startsector, size_t nsectors, - bool readonly) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_lun_s *lun; - FAR struct inode *inode; - struct geometry geo; - int ret; - -#ifdef CONFIG_DEBUG - if (!alloc || !drvrpath || startsector < 0 || nsectors < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINLUNINVALIDARGS1), 0); - return -EINVAL; - } -#endif - - priv = &alloc->dev; - -#ifdef CONFIG_DEBUG - if (!priv->luntab) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INTERNALCONFUSION1), 0); - return -EIO; - } - - if (lunno > priv->nluns) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINDLUNINVALIDARGS2), 0); - return -EINVAL; - } -#endif - - lun = &priv->luntab[lunno]; - -#ifdef CONFIG_DEBUG - if (lun->inode != NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_LUNALREADYBOUND), 0); - return -EBUSY; - } -#endif - - /* Open the block driver */ - - ret = open_blockdriver(drvrpath, 0, &inode); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BLKDRVEOPEN), 0); - return ret; - } - - /* Get the drive geometry */ - - if (!inode || !inode->u.i_bops || !inode->u.i_bops->geometry || - inode->u.i_bops->geometry(inode, &geo) != OK || !geo.geo_available) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_NOGEOMETRY), 0); - return -ENODEV; - } - - /* Verify that the partition parameters are valid */ - - if (startsector >= geo.geo_nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINDLUNINVALIDARGS3), 0); - return -EDOM; - } - else if (nsectors == 0) - { - nsectors = geo.geo_nsectors - startsector; - } - else if (startsector + nsectors >= geo.geo_nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINDLUNINVALIDARGS4), 0); - return -EDOM; - } - - /* Initialize the LUN structure */ - - memset(lun, 0, sizeof(struct usbmsc_lun_s *)); - - /* Allocate an I/O buffer big enough to hold one hardware sector. SCSI commands - * are processed one at a time so all LUNs may share a single I/O buffer. The - * I/O buffer will be allocated so that is it as large as the largest block - * device sector size - */ - - if (!priv->iobuffer) - { - priv->iobuffer = (uint8_t*)kmalloc(geo.geo_sectorsize); - if (!priv->iobuffer) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCIOBUFFER), geo.geo_sectorsize); - return -ENOMEM; - } - priv->iosize = geo.geo_sectorsize; - } - else if (priv->iosize < geo.geo_sectorsize) - { - void *tmp; - tmp = (uint8_t*)realloc(priv->iobuffer, geo.geo_sectorsize); - if (!tmp) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_REALLOCIOBUFFER), geo.geo_sectorsize); - return -ENOMEM; - } - - priv->iobuffer = (uint8_t*)tmp; - priv->iosize = geo.geo_sectorsize; - } - - lun->inode = inode; - lun->startsector = startsector; - lun->nsectors = nsectors; - lun->sectorsize = geo.geo_sectorsize; - - /* If the driver does not support the write method, then this is read-only */ - - if (!inode->u.i_bops->write) - { - lun->readonly = true; - } - return OK; -} - -/**************************************************************************** - * Name: usbmsc_unbindlun - * - * Description: - * Un-bind the block driver for the specified LUN - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * lun - the LUN to unbind from - * - * Returned Value: - * 0 on success; a negated errno on failure. - * - ****************************************************************************/ - -int usbmsc_unbindlun(FAR void *handle, unsigned int lunno) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_lun_s *lun; - int ret; - -#ifdef CONFIG_DEBUG - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNBINDLUNINVALIDARGS1), 0); - return -EINVAL; - } -#endif - - priv = &alloc->dev; - -#ifdef CONFIG_DEBUG - if (!priv->luntab) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INTERNALCONFUSION2), 0); - return -EIO; - } - - if (lunno > priv->nluns) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNBINDLUNINVALIDARGS2), 0); - return -EINVAL; - } -#endif - - lun = &priv->luntab[lunno]; - pthread_mutex_lock(&priv->mutex); - -#ifdef CONFIG_DEBUG - if (lun->inode == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_LUNNOTBOUND), 0); - ret = -EBUSY; - } - else -#endif - { - /* Close the block driver */ - - usbmsc_lununinitialize(lun); - ret = OK; - } - - pthread_mutex_unlock(&priv->mutex); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_exportluns - * - * Description: - * After all of the LUNs have been bound, this function may be called - * in order to export those LUNs in the USB storage device. - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * - * Returned Value: - * 0 on success; a negated errno on failure - * - ****************************************************************************/ - -#ifdef CONFIG_USBMSC_COMPOSITE -static -#endif -int usbmsc_exportluns(FAR void *handle) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_driver_s *drvr; - irqstate_t flags; -#ifdef SDCC - pthread_attr_t attr; -#endif - int ret; - -#ifdef CONFIG_DEBUG - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EXPORTLUNSINVALIDARGS), 0); - return -ENXIO; - } -#endif - - priv = &alloc->dev; - drvr = &alloc->drvr; - - /* Start the worker thread */ - - pthread_mutex_lock(&priv->mutex); - priv->thstate = USBMSC_STATE_NOTSTARTED; - priv->theventset = USBMSC_EVENT_NOEVENTS; - -#ifdef SDCC - (void)pthread_attr_init(&attr); - ret = pthread_create(&priv->thread, &attr, usbmsc_workerthread, (pthread_addr_t)priv); -#else - ret = pthread_create(&priv->thread, NULL, usbmsc_workerthread, (pthread_addr_t)priv); -#endif - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_THREADCREATE), (uint16_t)-ret); - goto errout_with_mutex; - } - - /* Register the USB storage class driver (unless we are part of a composite device) */ - -#ifndef CONFIG_USBMSC_COMPOSITE - ret = usbdev_register(&drvr->drvr); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DEVREGISTER), (uint16_t)-ret); - goto errout_with_mutex; - } -#endif - - /* Signal to start the thread */ - - flags = irqsave(); - priv->theventset |= USBMSC_EVENT_READY; - pthread_cond_signal(&priv->cond); - irqrestore(flags); - -errout_with_mutex: - pthread_mutex_unlock(&priv->mutex); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_classobject - * - * Description: - * Register USB mass storage device and return the class object. - * - * Input Parameters: - * classdev - The location to return the CDC serial class' device - * instance. - * - * Returned Value: - * 0 on success; a negated errno on failure - - * - ****************************************************************************/ - -#ifdef CONFIG_USBMSC_COMPOSITE -int usbmsc_classobject(FAR void *handle, - FAR struct usbdevclass_driver_s **classdev) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - int ret; - - DEBUGASSERT(handle && classdev); - - /* Export the LUNs as with the "standalone" USB mass storage driver, but - * don't register the class instance with the USB device infrastructure. - */ - - ret = usbmsc_exportluns(handle); - if (ret == OK) - { - /* On sucess, return an (typed) instance of the class instance */ - - *classdev = &alloc->drvr.drvr; - } - return ret; -} -#endif - -/**************************************************************************** - * Name: usbmsc_uninitialize - * - * Description: - * Un-initialize the USB storage class driver - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * - * Returned Value: - * None - * - ****************************************************************************/ - -void usbmsc_uninitialize(FAR void *handle) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - irqstate_t flags; -#ifdef SDCC - pthread_addr_t result1, result2; - pthread_attr_t attr; -#endif - void *value; - int i; - -#ifdef CONFIG_DEBUG - if (!handle) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNINITIALIZEINVALIDARGS), 0); - return; - } -#endif - priv = &alloc->dev; - - /* If the thread hasn't already exitted, tell it to exit now */ - - if (priv->thstate != USBMSC_STATE_NOTSTARTED) - { - /* The thread was started.. Is it still running? */ - - pthread_mutex_lock(&priv->mutex); - if (priv->thstate != USBMSC_STATE_TERMINATED) - { - /* Yes.. Ask the thread to stop */ - - flags = irqsave(); - priv->theventset |= USBMSC_EVENT_TERMINATEREQUEST; - pthread_cond_signal(&priv->cond); - irqrestore(flags); - } - pthread_mutex_unlock(&priv->mutex); - - /* Wait for the thread to exit. This is necessary even if the - * thread has already exitted in order to collect the join - * garbage - */ - - (void)pthread_join(priv->thread, &value); - } - priv->thread = 0; - - /* Unregister the driver (unless we are a part of a composite device */ - -#ifndef CONFIG_USBMSC_COMPOSITE - usbdev_unregister(&alloc->drvr.drvr); -#endif - - /* Uninitialize and release the LUNs */ - - for (i = 0; i < priv->nluns; ++i) - { - usbmsc_lununinitialize(&priv->luntab[i]); - } - kfree(priv->luntab); - - /* Release the I/O buffer */ - - if (priv->iobuffer) - { - kfree(priv->iobuffer); - } - - /* Uninitialize and release the driver structure */ - - pthread_mutex_destroy(&priv->mutex); - pthread_cond_destroy(&priv->cond); - - kfree(priv); -} diff --git a/nuttx/drivers/usbdev/usbmsc.h b/nuttx/drivers/usbdev/usbmsc.h deleted file mode 100644 index da35ae923..000000000 --- a/nuttx/drivers/usbdev/usbmsc.h +++ /dev/null @@ -1,694 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/usbmsc.h - * - * Copyright (C) 2008-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Mass storage class device. Bulk-only with SCSI subclass. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_USBDEV_USBMSC_H -#define __DRIVERS_USBDEV_USBMSC_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* If the USB mass storage device is configured as part of a composite device - * then both CONFIG_USBDEV_COMPOSITE and CONFIG_USBMSC_COMPOSITE must be - * defined. - */ - -#ifndef CONFIG_USBDEV_COMPOSITE -# undef CONFIG_USBMSC_COMPOSITE -#endif - -#if defined(CONFIG_USBMSC_COMPOSITE) && !defined(CONFIG_USBMSC_STRBASE) -# define CONFIG_USBMSC_STRBASE (4) -#endif - -/* Interface IDs. If the mass storage driver is built as a component of a - * composite device, then the interface IDs may need to be offset. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE -# undef CONFIG_USBMSC_IFNOBASE -# define CONFIG_USBMSC_IFNOBASE 0 -#endif - -#ifndef CONFIG_USBMSC_IFNOBASE -# define CONFIG_USBMSC_IFNOBASE 0 -#endif - -/* Number of requests in the write queue */ - -#ifndef CONFIG_USBMSC_NWRREQS -# define CONFIG_USBMSC_NWRREQS 4 -#endif - -/* Number of requests in the read queue */ - -#ifndef CONFIG_USBMSC_NRDREQS -# define CONFIG_USBMSC_NRDREQS 4 -#endif - -/* Logical endpoint numbers / max packet sizes */ - -#ifndef CONFIG_USBMSC_EPBULKOUT -# warning "EPBULKOUT not defined in the configuration" -# define CONFIG_USBMSC_EPBULKOUT 2 -#endif - -#ifndef CONFIG_USBMSC_EPBULKIN -# warning "EPBULKIN not defined in the configuration" -# define CONFIG_USBMSC_EPBULKIN 3 -#endif - -/* Packet and request buffer sizes */ - -#ifndef CONFIG_USBMSC_COMPOSITE -# ifndef CONFIG_USBMSC_EP0MAXPACKET -# define CONFIG_USBMSC_EP0MAXPACKET 64 -# endif -#endif - -#ifndef CONFIG_USBMSC_BULKINREQLEN -# ifdef CONFIG_USBDEV_DUALSPEED -# define CONFIG_USBMSC_BULKINREQLEN 512 -# else -# define CONFIG_USBMSC_BULKINREQLEN 64 -# endif -#else -# ifdef CONFIG_USBDEV_DUALSPEED -# if CONFIG_USBMSC_BULKINREQLEN < 512 -# warning "Bulk in buffer size smaller than max packet" -# undef CONFIG_USBMSC_BULKINREQLEN -# define CONFIG_USBMSC_BULKINREQLEN 512 -# endif -# else -# if CONFIG_USBMSC_BULKINREQLEN < 64 -# warning "Bulk in buffer size smaller than max packet" -# undef CONFIG_USBMSC_BULKINREQLEN -# define CONFIG_USBMSC_BULKINREQLEN 64 -# endif -# endif -#endif - -#ifndef CONFIG_USBMSC_BULKOUTREQLEN -# ifdef CONFIG_USBDEV_DUALSPEED -# define CONFIG_USBMSC_BULKOUTREQLEN 512 -# else -# define CONFIG_USBMSC_BULKOUTREQLEN 64 -# endif -#else -# ifdef CONFIG_USBDEV_DUALSPEED -# if CONFIG_USBMSC_BULKOUTREQLEN < 512 -# warning "Bulk in buffer size smaller than max packet" -# undef CONFIG_USBMSC_BULKOUTREQLEN -# define CONFIG_USBMSC_BULKOUTREQLEN 512 -# endif -# else -# if CONFIG_USBMSC_BULKOUTREQLEN < 64 -# warning "Bulk in buffer size smaller than max packet" -# undef CONFIG_USBMSC_BULKOUTREQLEN -# define CONFIG_USBMSC_BULKOUTREQLEN 64 -# endif -# endif -#endif - -/* Vendor and product IDs and strings */ - -#ifndef CONFIG_USBMSC_COMPOSITE -# ifndef CONFIG_USBMSC_VENDORID -# warning "CONFIG_USBMSC_VENDORID not defined" -# define CONFIG_USBMSC_VENDORID 0x584e -# endif - -# ifndef CONFIG_USBMSC_PRODUCTID -# warning "CONFIG_USBMSC_PRODUCTID not defined" -# define CONFIG_USBMSC_PRODUCTID 0x5342 -# endif - -# ifndef CONFIG_USBMSC_VERSIONNO -# define CONFIG_USBMSC_VERSIONNO (0x0399) -# endif - -# ifndef CONFIG_USBMSC_VENDORSTR -# warning "No Vendor string specified" -# define CONFIG_USBMSC_VENDORSTR "NuttX" -# endif - -# ifndef CONFIG_USBMSC_PRODUCTSTR -# warning "No Product string specified" -# define CONFIG_USBMSC_PRODUCTSTR "USBdev Storage" -# endif - -# undef CONFIG_USBMSC_SERIALSTR -# define CONFIG_USBMSC_SERIALSTR "0101" -#endif - -#undef CONFIG_USBMSC_CONFIGSTR -#define CONFIG_USBMSC_CONFIGSTR "Bulk" - -/* Debug -- must be consistent with include/debug.h */ - -#ifdef CONFIG_CPP_HAVE_VARARGS -# ifdef CONFIG_DEBUG -# ifdef CONFIG_ARCH_LOWPUTC -# define dbgprintf(format, arg...) lowsyslog(format, ##arg) -# else -# define dbgprintf(format, arg...) syslog(format, ##arg) -# endif -# else -# define dbgprintf(x...) -# endif -#else -# ifdef CONFIG_DEBUG -# ifdef CONFIG_ARCH_LOWPUTC -# define dbgprintf lowsyslog -# else -# define dbgprintf syslog -# endif -# else -# define dbgprintf (void) -# endif -#endif - -/* Packet and request buffer sizes */ - -#ifndef CONFIG_USBMSC_EP0MAXPACKET -# define CONFIG_USBMSC_EP0MAXPACKET 64 -#endif - -/* USB Controller */ - -#ifndef CONFIG_USBDEV_SELFPOWERED -# define SELFPOWERED USB_CONFIG_ATTR_SELFPOWER -#else -# define SELFPOWERED (0) -#endif - -#ifndef CONFIG_USBDEV_REMOTEWAKEUP -# define REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP -#else -# define REMOTEWAKEUP (0) -#endif - -#ifndef CONFIG_USBDEV_MAXPOWER -# define CONFIG_USBDEV_MAXPOWER 100 -#endif - -/* Current state of the worker thread */ - -#define USBMSC_STATE_NOTSTARTED (0) /* Thread has not yet been started */ -#define USBMSC_STATE_STARTED (1) /* Started, but is not yet initialized */ -#define USBMSC_STATE_IDLE (2) /* Started and waiting for commands */ -#define USBMSC_STATE_CMDPARSE (3) /* Processing a received command */ -#define USBMSC_STATE_CMDREAD (4) /* Processing a SCSI read command */ -#define USBMSC_STATE_CMDWRITE (5) /* Processing a SCSI write command */ -#define USBMSC_STATE_CMDFINISH (6) /* Finish command processing */ -#define USBMSC_STATE_CMDSTATUS (7) /* Processing the final status of the command */ -#define USBMSC_STATE_TERMINATED (8) /* Thread has exitted */ - -/* Event communicated to worker thread */ - -#define USBMSC_EVENT_NOEVENTS (0) /* There are no outstanding events */ -#define USBMSC_EVENT_READY (1 << 0) /* Initialization is complete */ -#define USBMSC_EVENT_RDCOMPLETE (1 << 1) /* A read has completed there is data to be processed */ -#define USBMSC_EVENT_WRCOMPLETE (1 << 2) /* A write has completed and a request is available */ -#define USBMSC_EVENT_TERMINATEREQUEST (1 << 3) /* Shutdown requested */ -#define USBMSC_EVENT_DISCONNECT (1 << 4) /* USB disconnect received */ -#define USBMSC_EVENT_RESET (1 << 5) /* USB storage setup reset received */ -#define USBMSC_EVENT_CFGCHANGE (1 << 6) /* USB setup configuration change received */ -#define USBMSC_EVENT_IFCHANGE (1 << 7) /* USB setup interface change received */ -#define USBMSC_EVENT_ABORTBULKOUT (1 << 8) /* SCSI receive failure */ - -/* SCSI command flags (passed to usbmsc_setupcmd()) */ - -#define USBMSC_FLAGS_DIRMASK (0x03) /* Bits 0-1: Data direction */ -#define USBMSC_FLAGS_DIRNONE (0x00) /* No data to send */ -#define USBMSC_FLAGS_DIRHOST2DEVICE (0x01) /* Host-to-device */ -#define USBMSC_FLAGS_DIRDEVICE2HOST (0x02) /* Device-to-host */ -#define USBMSC_FLAGS_BLOCKXFR (0x04) /* Bit 2: Command is a block transfer request */ -#define USBMSC_FLAGS_LUNNOTNEEDED (0x08) /* Bit 3: Command does not require a valid LUN */ -#define USBMSC_FLAGS_UACOKAY (0x10) /* Bit 4: Command OK if unit attention condition */ -#define USBMSC_FLAGS_RETAINSENSEDATA (0x20) /* Bit 5: Do not clear sense data */ - -/* Descriptors **************************************************************/ - -/* Big enough to hold our biggest descriptor */ - -#define USBMSC_MXDESCLEN (64) - -/* String language */ - -#define USBMSC_STR_LANGUAGE (0x0409) /* en-us */ - -/* Descriptor strings */ - -#ifndef CONFIG_USBMSC_COMPOSITE -# define USBMSC_MANUFACTURERSTRID (1) -# define USBMSC_PRODUCTSTRID (2) -# define USBMSC_SERIALSTRID (3) -# define USBMSC_CONFIGSTRID (4) -# define USBMSC_INTERFACESTRID USBMSC_CONFIGSTRID - -# undef CONFIG_USBMSC_STRBASE -# define CONFIG_USBMSC_STRBASE (0) -#else -# define USBMSC_INTERFACESTRID (CONFIG_USBMSC_STRBASE+1) -#endif - -#define USBMSC_LASTSTRID USBMSC_INTERFACESTRID -#define USBMSC_NSTRIDS (USBMSC_LASTSTRID - CONFIG_USBMSC_STRBASE) - -#define USBMSC_NCONFIGS (1) /* Number of configurations supported */ - -/* Configuration Descriptor */ - -#define USBMSC_NINTERFACES (1) /* Number of interfaces in the configuration */ -#define USBMSC_INTERFACEID (CONFIG_USBMSC_IFNOBASE+0) -#define USBMSC_ALTINTERFACEID (0) - -#define USBMSC_CONFIGIDNONE (0) /* Config ID means to return to address mode */ -#define USBMSC_CONFIGID (1) /* The only supported configuration ID */ - -/* Interface description */ - -#define USBMSC_NENDPOINTS (2) /* Number of endpoints in the interface */ - -/* Endpoint configuration */ - -#define USBMSC_EPOUTBULK_ADDR (CONFIG_USBMSC_EPBULKOUT) -#define USBMSC_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK) - -#define USBMSC_EPINBULK_ADDR (USB_DIR_IN|CONFIG_USBMSC_EPBULKIN) -#define USBMSC_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK) - -#define USBMSC_HSBULKMAXPACKET (512) -#define USBMSC_HSBULKMXPKTSHIFT (9) -#define USBMSC_HSBULKMXPKTMASK (0x000001ff) -#define USBMSC_FSBULKMAXPACKET (64) -#define USBMSC_FSBULKMXPKTSHIFT (6) -#define USBMSC_FSBULKMXPKTMASK (0x0000003f) - -/* Macros for dual speed vs. full speed only operation */ - -#ifdef CONFIG_USBDEV_DUALSPEED -# define USBMSC_EPBULKINDESC(hs) \ - usbmsc_getepdesc((hs) ? USBMSC_EPHSBULKIN : USBMSC_EPFSBULKIN) -# define USBMSC_EPBULKOUTDESC(hs) \ - usbmsc_getepdesc((hs) ? USBMSC_EPHSBULKOUT : USBMSC_EPFSBULKOUT) -# define USBMSC_BULKMAXPACKET(hs) \ - ((hs) ? USBMSC_HSBULKMAXPACKET : USBMSC_FSBULKMAXPACKET) -# define USBMSC_BULKMXPKTSHIFT(d) \ - (((d)->speed==USB_SPEED_HIGH) ? USBMSC_HSBULKMXPKTSHIFT : USBMSC_FSBULKMXPKTSHIFT) -# define USBMSC_BULKMXPKTMASK(d) \ - (((d)->speed==USB_SPEED_HIGH) ? USBMSC_HSBULKMXPKTMASK : USBMSC_FSBULKMXPKTMASK) -#else -# define USBMSC_EPBULKINDESC(d) usbmsc_getepdesc(USBMSC_EPFSBULKIN) -# define USBMSC_EPBULKOUTDESC(d) usbmsc_getepdesc(USBMSC_EPFSBULKOUT) -# define USBMSC_BULKMAXPACKET(hs) USBMSC_FSBULKMAXPACKET -# define USBMSC_BULKMXPKTSHIFT(d) USBMSC_FSBULKMXPKTSHIFT -# define USBMSC_BULKMXPKTMASK(d) USBMSC_FSBULKMXPKTMASK -#endif - -/* Configuration descriptor size */ - -#ifndef CONFIG_USBMSC_COMPOSITE - -/* Number of individual descriptors in the configuration descriptor: - * (1) Configuration descriptor + (1) interface descriptor + (2) interface - * descriptors. - */ - -# define USBMSC_CFGGROUP_SIZE (4) - -/* The size of the config descriptor: (9 + 9 + 2*7) = 32 */ - -# define SIZEOF_USBMSC_CFGDESC \ - (USB_SIZEOF_CFGDESC + USB_SIZEOF_IFDESC + USBMSC_NENDPOINTS * USB_SIZEOF_EPDESC) - -#else - -/* Number of individual descriptors in the configuration descriptor: - * (1) interface descriptor + (2) interface descriptors. - */ - -# define USBMSC_CFGGROUP_SIZE (3) - -/* The size of the config descriptor: (9 + 2*7) = 23 */ - -# define SIZEOF_USBMSC_CFGDESC \ - (USB_SIZEOF_IFDESC + USBMSC_NENDPOINTS * USB_SIZEOF_EPDESC) - -#endif - -/* Block driver helpers *****************************************************/ - -#define USBMSC_DRVR_READ(l,b,s,n) ((l)->inode->u.i_bops->read((l)->inode,b,s,n)) -#define USBMSC_DRVR_WRITE(l,b,s,n) ((l)->inode->u.i_bops->write((l)->inode,b,s,n)) -#define USBMSC_DRVR_GEOMETRY(l,g) ((l)->inode->u.i_bops->geometry((l)->inode,g)) - -/* Everpresent MIN/MAX macros ***********************************************/ - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef MAX -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -/**************************************************************************** - * Public Types - ****************************************************************************/ -/* Endpoint descriptors */ - -enum usbmsc_epdesc_e -{ - USBMSC_EPFSBULKOUT = 0, /* Full speed bulk OUT endpoint descriptor */ - USBMSC_EPFSBULKIN /* Full speed bulk IN endpoint descriptor */ -#ifdef CONFIG_USBDEV_DUALSPEED - , - USBMSC_EPHSBULKOUT, /* High speed bulk OUT endpoint descriptor */ - USBMSC_EPHSBULKIN /* High speed bulk IN endpoint descriptor */ -#endif -}; - -/* Container to support a list of requests */ - -struct usbmsc_req_s -{ - FAR struct usbmsc_req_s *flink; /* Implements a singly linked list */ - FAR struct usbdev_req_s *req; /* The contained request */ -}; - -/* This structure describes one LUN: */ - -struct usbmsc_lun_s -{ - struct inode *inode; /* Inode structure of open'ed block driver */ - uint8_t readonly:1; /* Media is read-only */ - uint8_t locked:1; /* Media removal is prevented */ - uint16_t sectorsize; /* The size of one sector */ - uint32_t sd; /* Sense data */ - uint32_t sdinfo; /* Sense data information */ - uint32_t uad; /* Unit needs attention data */ - off_t startsector; /* Sector offset to start of partition */ - size_t nsectors; /* Number of sectors in the partition */ -}; - -/* Describes the overall state of the driver */ - -struct usbmsc_dev_s -{ - FAR struct usbdev_s *usbdev; /* usbdev driver pointer (Non-null if registered) */ - - /* Worker thread interface */ - - pthread_t thread; /* The worker thread */ - pthread_mutex_t mutex; /* Mutually exclusive access to resources*/ - pthread_cond_t cond; /* Used to signal worker thread */ - volatile uint8_t thstate; /* State of the worker thread */ - volatile uint16_t theventset; /* Set of pending events signaled to worker thread */ - volatile uint8_t thvalue; /* Value passed with the event (must persist) */ - - /* Storage class configuration and state */ - - uint8_t nluns:4; /* Number of LUNs */ - uint8_t config; /* Configuration number */ - - /* Endpoints */ - - FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */ - FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */ - FAR struct usbdev_req_s *ctrlreq; /* Control request (for ep0 setup responses) */ - - /* SCSI command processing */ - - struct usbmsc_lun_s *lun; /* Currently selected LUN */ - struct usbmsc_lun_s *luntab; /* Allocated table of all LUNs */ - uint8_t cdb[USBMSC_MAXCDBLEN]; /* Command data (cdb[]) from CBW */ - uint8_t phaseerror:1; /* Need to send phase sensing status */ - uint8_t shortpacket:1; /* Host transmission stopped unexpectedly */ - uint8_t cbwdir:2; /* Direction from CBW. See USBMSC_FLAGS_DIR* definitions */ - uint8_t cdblen; /* Length of cdb[] from CBW */ - uint8_t cbwlun; /* LUN from the CBW */ - uint16_t nsectbytes; /* Bytes buffered in iobuffer[] */ - uint16_t nreqbytes; /* Bytes buffered in head write requests */ - uint16_t iosize; /* Size of iobuffer[] */ - uint32_t cbwlen; /* Length of data from CBW */ - uint32_t cbwtag; /* Tag from the CBW */ - union - { - uint32_t xfrlen; /* Read/Write: Sectors remaining to be transferred */ - uint32_t alloclen; /* Other device-to-host: Host allocation length */ - } u; - uint32_t sector; /* Current sector (relative to lun->startsector) */ - uint32_t residue; /* Untransferred amount reported in the CSW */ - uint8_t *iobuffer; /* Buffer for data transfers */ - - /* Write request list */ - - struct sq_queue_s wrreqlist; /* List of empty write request containers */ - struct sq_queue_s rdreqlist; /* List of filled read request containers */ - - /* Pre-allocated write request containers. The write requests will - * be linked in a free list (wrreqlist), and used to send requests to - * EPBULKIN; Read requests will be queued in the EBULKOUT. - */ - - struct usbmsc_req_s wrreqs[CONFIG_USBMSC_NWRREQS]; - struct usbmsc_req_s rdreqs[CONFIG_USBMSC_NRDREQS]; -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -# define EXTERN extern "C" -extern "C" -{ -#else -# define EXTERN extern -#endif - -/* String *******************************************************************/ - -/* Mass storage class vendor/product/serial number strings */ - -#ifndef CONFIG_USBMSC_COMPOSITE -EXTERN const char g_mscvendorstr[]; -EXTERN const char g_mscproductstr[]; -EXTERN const char g_mscserialstr[]; - -/* If we are using a composite device, then vendor/product/serial number strings - * are provided by the composite device logic. - */ - -#else -EXTERN const char g_compvendorstr[]; -EXTERN const char g_compproductstr[]; -EXTERN const char g_compserialstr[]; - -#define g_mscvendorstr g_compvendorstr -#define g_mscproductstr g_compproductstr -#define g_mscserialstr g_compserialstr -#endif -/************************************************************************************ - * Public Function Prototypes - ************************************************************************************/ - -/************************************************************************************ - * Name: usbmsc_mkstrdesc - * - * Description: - * Construct a string descriptor - * - ************************************************************************************/ - -struct usb_strdesc_s; -int usbmsc_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc); - -/************************************************************************************ - * Name: usbmsc_getepdesc - * - * Description: - * Return a pointer to the raw device descriptor - * - ************************************************************************************/ - -#ifndef CONFIG_USBMSC_COMPOSITE -FAR const struct usb_devdesc_s *usbmsc_getdevdesc(void); -#endif - -/************************************************************************************ - * Name: usbmsc_getepdesc - * - * Description: - * Return a pointer to the raw endpoint descriptor (used for configuring endpoints) - * - ************************************************************************************/ - -struct usb_epdesc_s; -FAR const struct usb_epdesc_s *usbmsc_getepdesc(enum usbmsc_epdesc_e epid); - -/************************************************************************************ - * Name: usbmsc_mkcfgdesc - * - * Description: - * Construct the configuration descriptor - * - ************************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf, uint8_t speed, uint8_t type); -#else -int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf); -#endif - -/************************************************************************************ - * Name: usbmsc_getqualdesc - * - * Description: - * Return a pointer to the raw qual descriptor - * - ************************************************************************************/ - -#if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) -FAR const struct usb_qualdesc_s *usbmsc_getqualdesc(void); -#endif - -/**************************************************************************** - * Name: usbmsc_workerthread - * - * Description: - * This is the main function of the USB storage worker thread. It loops - * until USB-related events occur, then processes those events accordingly - * - ****************************************************************************/ - -EXTERN void *usbmsc_workerthread(void *arg); - -/**************************************************************************** - * Name: usbmsc_setconfig - * - * Description: - * Set the device configuration by allocating and configuring endpoints and - * by allocating and queue read and write requests. - * - ****************************************************************************/ - -EXTERN int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config); - -/**************************************************************************** - * Name: usbmsc_resetconfig - * - * Description: - * Mark the device as not configured and disable all endpoints. - * - ****************************************************************************/ - -EXTERN void usbmsc_resetconfig(FAR struct usbmsc_dev_s *priv); - -/**************************************************************************** - * Name: usbmsc_wrcomplete - * - * Description: - * Handle completion of write request. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -EXTERN void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/**************************************************************************** - * Name: usbmsc_rdcomplete - * - * Description: - * Handle completion of read request on the bulk OUT endpoint. This - * is handled like the receipt of serial data on the "UART" - * - ****************************************************************************/ - -EXTERN void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/**************************************************************************** - * Name: usbmsc_deferredresponse - * - * Description: - * Some EP0 setup request cannot be responded to immediately becuase they - * require some asynchronous action from the SCSI worker thread. This - * function is provided for the SCSI thread to make that deferred response. - * The specific requests that require this deferred response are: - * - * 1. USB_REQ_SETCONFIGURATION, - * 2. USB_REQ_SETINTERFACE, or - * 3. USBMSC_REQ_MSRESET - * - * In all cases, the success reponse is a zero-length packet; the failure - * response is an EP0 stall. - * - * Input parameters: - * priv - Private state structure for this USB storage instance - * stall - true is the action failed and a stall is required - * - ****************************************************************************/ - -EXTERN void usbmsc_deferredresponse(FAR struct usbmsc_dev_s *priv, bool failed); - -#undef EXTERN -#if defined(__cplusplus) -} -#endif - -#endif /* #define __DRIVERS_USBDEV_USBMSC_H */ diff --git a/nuttx/drivers/usbdev/usbmsc_desc.c b/nuttx/drivers/usbdev/usbmsc_desc.c deleted file mode 100644 index 6d7561b3f..000000000 --- a/nuttx/drivers/usbdev/usbmsc_desc.c +++ /dev/null @@ -1,421 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/usbmsc_desc.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "usbmsc.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ -/* Descriptors **************************************************************/ -/* Device descriptor. If the USB mass storage device is configured as part - * of a composite device, then the device descriptor will be provided by the - * composite device logic. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE -static const struct usb_devdesc_s g_devdesc = -{ - USB_SIZEOF_DEVDESC, /* len */ - USB_DESC_TYPE_DEVICE, /* type */ - {LSBYTE(0x0200), MSBYTE(0x0200)}, /* usb */ - USB_CLASS_PER_INTERFACE, /* classid */ - 0, /* subclass */ - 0, /* protocol */ - CONFIG_USBMSC_EP0MAXPACKET, /* maxpacketsize */ - { /* vendor */ - LSBYTE(CONFIG_USBMSC_VENDORID), - MSBYTE(CONFIG_USBMSC_VENDORID) - }, - { /* product */ - LSBYTE(CONFIG_USBMSC_PRODUCTID), - MSBYTE(CONFIG_USBMSC_PRODUCTID) }, - { /* device */ - LSBYTE(CONFIG_USBMSC_VERSIONNO), - MSBYTE(CONFIG_USBMSC_VERSIONNO) - }, - USBMSC_MANUFACTURERSTRID, /* imfgr */ - USBMSC_PRODUCTSTRID, /* iproduct */ - USBMSC_SERIALSTRID, /* serno */ - USBMSC_NCONFIGS /* nconfigs */ -}; -#endif - -/* Configuration descriptor If the USB mass storage device is configured as part - * of a composite device, then the configuration descriptor will be provided by the - * composite device logic. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE -static const struct usb_cfgdesc_s g_cfgdesc = -{ - USB_SIZEOF_CFGDESC, /* len */ - USB_DESC_TYPE_CONFIG, /* type */ - { /* totallen */ - LSBYTE(SIZEOF_USBMSC_CFGDESC), - MSBYTE(SIZEOF_USBMSC_CFGDESC) - }, - USBMSC_NINTERFACES, /* ninterfaces */ - USBMSC_CONFIGID, /* cfgvalue */ - USBMSC_CONFIGSTRID, /* icfg */ - USB_CONFIG_ATTR_ONE|SELFPOWERED|REMOTEWAKEUP, /* attr */ - (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */ -}; -#endif - -/* Single interface descriptor */ - -static const struct usb_ifdesc_s g_ifdesc = -{ - USB_SIZEOF_IFDESC, /* len */ - USB_DESC_TYPE_INTERFACE, /* type */ - USBMSC_INTERFACEID, /* ifno */ - USBMSC_ALTINTERFACEID, /* alt */ - USBMSC_NENDPOINTS, /* neps */ - USB_CLASS_MASS_STORAGE, /* classid */ - USBMSC_SUBCLASS_SCSI, /* subclass */ - USBMSC_PROTO_BULKONLY, /* protocol */ - USBMSC_INTERFACESTRID /* iif */ -}; - -/* Endpoint descriptors */ - -static const struct usb_epdesc_s g_fsepbulkoutdesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPOUTBULK_ADDR, /* addr */ - USBMSC_EPOUTBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_FSBULKMAXPACKET), - MSBYTE(USBMSC_FSBULKMAXPACKET) - }, - 0 /* interval */ -}; - -static const struct usb_epdesc_s g_fsepbulkindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPINBULK_ADDR, /* addr */ - USBMSC_EPINBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_FSBULKMAXPACKET), - MSBYTE(USBMSC_FSBULKMAXPACKET) - }, - 0 /* interval */ -}; - -#ifdef CONFIG_USBDEV_DUALSPEED -#ifndef CONFIG_USBMSC_COMPOSITE -static const struct usb_qualdesc_s g_qualdesc = -{ - USB_SIZEOF_QUALDESC, /* len */ - USB_DESC_TYPE_DEVICEQUALIFIER, /* type */ - { /* usb */ - LSBYTE(0x0200), - MSBYTE(0x0200) - }, - USB_CLASS_PER_INTERFACE, /* classid */ - 0, /* subclass */ - 0, /* protocol */ - CONFIG_USBMSC_EP0MAXPACKET, /* mxpacketsize */ - USBMSC_NCONFIGS, /* nconfigs */ - 0, /* reserved */ -}; -#endif - -static const struct usb_epdesc_s g_hsepbulkoutdesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPOUTBULK_ADDR, /* addr */ - USBMSC_EPOUTBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_HSBULKMAXPACKET), - MSBYTE(USBMSC_HSBULKMAXPACKET) - }, - 0 /* interval */ -}; - -static const struct usb_epdesc_s g_hsepbulkindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPINBULK_ADDR, /* addr */ - USBMSC_EPINBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_HSBULKMAXPACKET), - MSBYTE(USBMSC_HSBULKMAXPACKET) - }, - 0 /* interval */ -}; -#endif - -/**************************************************************************** - * Public Data - ****************************************************************************/ -/* Strings ******************************************************************/ - -#ifndef CONFIG_USBMSC_COMPOSITE -const char g_mscvendorstr[] = CONFIG_USBMSC_VENDORSTR; -const char g_mscproductstr[] = CONFIG_USBMSC_PRODUCTSTR; -const char g_mscserialstr[] = CONFIG_USBMSC_SERIALSTR; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbmsc_mkstrdesc - * - * Description: - * Construct a string descriptor - * - ****************************************************************************/ - -int usbmsc_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc) -{ - const char *str; - int len; - int ndata; - int i; - - switch (id) - { -#ifndef CONFIG_USBMSC_COMPOSITE - case 0: - { - /* Descriptor 0 is the language id */ - - strdesc->len = 4; - strdesc->type = USB_DESC_TYPE_STRING; - strdesc->data[0] = LSBYTE(USBMSC_STR_LANGUAGE); - strdesc->data[1] = MSBYTE(USBMSC_STR_LANGUAGE); - return 4; - } - - case USBMSC_MANUFACTURERSTRID: - str = g_mscvendorstr; - break; - - case USBMSC_PRODUCTSTRID: - str = g_mscproductstr; - break; - - case USBMSC_SERIALSTRID: - str = g_mscserialstr; - break; -#endif - - /* case USBMSC_CONFIGSTRID: */ - case USBMSC_INTERFACESTRID: - str = CONFIG_USBMSC_CONFIGSTR; - break; - - default: - return -EINVAL; - } - - /* The string is utf16-le. The poor man's utf-8 to utf16-le - * conversion below will only handle 7-bit en-us ascii - */ - - len = strlen(str); - for (i = 0, ndata = 0; i < len; i++, ndata += 2) - { - strdesc->data[ndata] = str[i]; - strdesc->data[ndata+1] = 0; - } - - strdesc->len = ndata+2; - strdesc->type = USB_DESC_TYPE_STRING; - return strdesc->len; -} - -/**************************************************************************** - * Name: usbmsc_getepdesc - * - * Description: - * Return a pointer to the raw device descriptor - * - ****************************************************************************/ - -#ifndef CONFIG_USBMSC_COMPOSITE -FAR const struct usb_devdesc_s *usbmsc_getdevdesc(void) -{ - return &g_devdesc; -} -#endif - -/**************************************************************************** - * Name: usbmsc_getepdesc - * - * Description: - * Return a pointer to the raw endpoint descriptor (used for configuring - * endpoints) - * - ****************************************************************************/ - -FAR const struct usb_epdesc_s *usbmsc_getepdesc(enum usbmsc_epdesc_e epid) -{ - switch (epid) - { - case USBMSC_EPFSBULKOUT: /* Full speed bulk OUT endpoint descriptor */ - return &g_fsepbulkoutdesc; - - case USBMSC_EPFSBULKIN: /* Full speed bulk IN endpoint descriptor */ - return &g_fsepbulkindesc; - -#ifdef CONFIG_USBDEV_DUALSPEED - case USBMSC_EPHSBULKOUT: /* High speed bulk OUT endpoint descriptor */ - return &g_hsepbulkoutdesc; - - case USBMSC_EPHSBULKIN: /* High speed bulk IN endpoint descriptor */ - return &g_hsepbulkindesc; -#endif - default: - return NULL; - } -}; - -/**************************************************************************** - * Name: usbmsc_mkcfgdesc - * - * Description: - * Construct the configuration descriptor - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -int16_t usbmsc_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type) -#else -int16_t usbmsc_mkcfgdesc(uint8_t *buf) -#endif -{ -#ifdef CONFIG_USBDEV_DUALSPEED - FAR const struct usb_epdesc_s *epdesc; - bool hispeed = (speed == USB_SPEED_HIGH); - uint16_t bulkmxpacket; -#endif - - /* Configuration descriptor. If the USB mass storage device is - * configured as part of a composite device, then the configuration - * descriptor will be provided by the composite device logic. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - memcpy(buf, &g_cfgdesc, USB_SIZEOF_CFGDESC); - buf += USB_SIZEOF_CFGDESC; -#endif - - /* Copy the canned interface descriptor */ - - memcpy(buf, &g_ifdesc, USB_SIZEOF_IFDESC); - buf += USB_SIZEOF_IFDESC; - - /* Make the two endpoint configurations */ - -#ifdef CONFIG_USBDEV_DUALSPEED - /* Check for switches between high and full speed */ - - hispeed = (speed == USB_SPEED_HIGH); - if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG) - { - hispeed = !hispeed; - } - - bulkmxpacket = USBMSC_BULKMAXPACKET(hispeed); - epdesc = USBMSC_EPBULKINDESC(hispeed); - memcpy(buf, epdesc, USB_SIZEOF_EPDESC); - buf += USB_SIZEOF_EPDESC; - - epdesc = USBMSC_EPBULKOUTDESC(hispeed); - memcpy(buf, epdesc, USB_SIZEOF_EPDESC); -#else - memcpy(buf, &g_fsepbulkoutdesc, USB_SIZEOF_EPDESC); - buf += USB_SIZEOF_EPDESC; - memcpy(buf, &g_fsepbulkindesc, USB_SIZEOF_EPDESC); -#endif - - return SIZEOF_USBMSC_CFGDESC; -} - -/**************************************************************************** - * Name: usbmsc_getqualdesc - * - * Description: - * Return a pointer to the raw qual descriptor - * - ****************************************************************************/ - -#if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) -FAR const struct usb_qualdesc_s *usbmsc_getqualdesc(void) -{ - return &g_qualdesc; -} -#endif - diff --git a/nuttx/drivers/usbdev/usbmsc_scsi.c b/nuttx/drivers/usbdev/usbmsc_scsi.c deleted file mode 100644 index ccc967618..000000000 --- a/nuttx/drivers/usbdev/usbmsc_scsi.c +++ /dev/null @@ -1,2667 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/usbmsc_scsi.c - * - * Copyright (C) 2008-2010, 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Mass storage class device. Bulk-only with SCSI subclass. - * - * References: - * "Universal Serial Bus Mass Storage Class, Specification Overview," - * Revision 1.2, USB Implementer's Forum, June 23, 2003. - * - * "Universal Serial Bus Mass Storage Class, Bulk-Only Transport," - * Revision 1.0, USB Implementer's Forum, September 31, 1999. - * - * "SCSI Primary Commands - 3 (SPC-3)," American National Standard - * for Information Technology, May 4, 2005 - * - * "SCSI Primary Commands - 4 (SPC-4)," American National Standard - * for Information Technology, July 19, 2008 - * - * "SCSI Block Commands -2 (SBC-2)," American National Standard - * for Information Technology, November 13, 2004 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "usbmsc.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -/* Race condition workaround found by David Hewson. This race condition - * "seems to relate to stalling the endpoint when a short response is - * generated which causes a residue to exist when the CSW would be returned. - * I think there's two issues here. The first being if the transfer which - * had just been queued before the stall had not completed then it wouldn’t - * then complete once the endpoint was stalled? The second is that the - * subsequent transfer for the CSW would be dropped on the floor (by the - * epsubmit() function) if the end point was still stalled as the control - * transfer to resume it hadn't occurred." - */ - -#define CONFIG_USBMSC_RACEWAR 1 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Debug ********************************************************************/ - -#if defined(CONFIG_DEBUG_VERBOSE) && defined (CONFIG_DEBUG_USB) -static void usbmsc_dumpdata(const char *msg, const uint8_t *buf, - int buflen); -#else -# define usbmsc_dumpdata(msg, buf, len) -#endif - -/* Utility Support Functions ************************************************/ - -static uint16_t usbmsc_getbe16(uint8_t *buf); -static uint32_t usbmsc_getbe32(uint8_t *buf); -static void usbmsc_putbe16(uint8_t * buf, uint16_t val); -static void usbmsc_putbe24(uint8_t *buf, uint32_t val); -static void usbmsc_putbe32(uint8_t *buf, uint32_t val); -#if 0 /* not used */ -static uint16_t usbmsc_getle16(uint8_t *buf); -#endif -static uint32_t usbmsc_getle32(uint8_t *buf); -#if 0 /* not used */ -static void usbmsc_putle16(uint8_t * buf, uint16_t val); -#endif -static void usbmsc_putle32(uint8_t *buf, uint32_t val); - -/* SCSI Command Processing **************************************************/ - -static inline int usbmsc_cmdtestunitready(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdrequestsense(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf); -static inline int usbmsc_cmdread6(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdwrite6(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdinquiry(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf); -static inline int usbmsc_cmdmodeselect6(FAR struct usbmsc_dev_s *priv); -static int usbmsc_modepage(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf, uint8_t pcpgcode, int *mdlen); -static inline int usbmsc_cmdmodesense6(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf); -static inline int usbmsc_cmdstartstopunit(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdpreventmediumremoval(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdreadformatcapacity(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf); -static inline int usbmsc_cmdreadcapacity10(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf); -static inline int usbmsc_cmdread10(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdwrite10(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdverify10(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdsynchronizecache10(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdmodeselect10(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdmodesense10(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf); -static inline int usbmsc_cmdread12(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_cmdwrite12(FAR struct usbmsc_dev_s *priv); -static inline int usbmsc_setupcmd(FAR struct usbmsc_dev_s *priv, - uint8_t cdblen, uint8_t flags); - -/* SCSI Worker Thread *******************************************************/ - -static int usbmsc_idlestate(FAR struct usbmsc_dev_s *priv); -static int usbmsc_cmdparsestate(FAR struct usbmsc_dev_s *priv); -static int usbmsc_cmdreadstate(FAR struct usbmsc_dev_s *priv); -static int usbmsc_cmdwritestate(FAR struct usbmsc_dev_s *priv); -static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv); -static int usbmsc_cmdstatusstate(FAR struct usbmsc_dev_s *priv); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Debug - ****************************************************************************/ - -/**************************************************************************** - * Name: usbmsc_dumpdata - ****************************************************************************/ - -#if defined(CONFIG_DEBUG_VERBOSE) && defined (CONFIG_DEBUG_USB) -static void usbmsc_dumpdata(const char *msg, const uint8_t *buf, int buflen) -{ - int i; - - dbgprintf("%s:", msg); - for (i = 0; i < buflen; i++) - { - dbgprintf(" %02x", buf[i]); - } - dbgprintf("\n"); -} -#endif - -/**************************************************************************** - * Utility Support Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbmsc_getbe16 - * - * Description: - * Get a 16-bit big-endian value reference by the byte pointer - * - ****************************************************************************/ - -static uint16_t usbmsc_getbe16(uint8_t *buf) -{ - return ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); -} - -/**************************************************************************** - * Name: usbmsc_getbe32 - * - * Description: - * Get a 32-bit big-endian value reference by the byte pointer - * - ****************************************************************************/ - -static uint32_t usbmsc_getbe32(uint8_t *buf) -{ - return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | - ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]); -} - -/**************************************************************************** - * Name: usbmsc_putbe16 - * - * Description: - * Store a 16-bit value in big-endian order to the location specified by - * a byte pointer - * - ****************************************************************************/ - -static void usbmsc_putbe16(uint8_t * buf, uint16_t val) -{ - buf[0] = val >> 8; - buf[1] = val; -} - -/**************************************************************************** - * Name: usbmsc_putbe24 - * - * Description: - * Store a 32-bit value in big-endian order to the location specified by - * a byte pointer - * - ****************************************************************************/ - -static void usbmsc_putbe24(uint8_t *buf, uint32_t val) -{ - buf[0] = val >> 16; - buf[1] = val >> 8; - buf[2] = val; -} - -/**************************************************************************** - * Name: usbmsc_putbe32 - * - * Description: - * Store a 32-bit value in big-endian order to the location specified by - * a byte pointer - * - ****************************************************************************/ - -static void usbmsc_putbe32(uint8_t *buf, uint32_t val) -{ - buf[0] = val >> 24; - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; -} - -/**************************************************************************** - * Name: usbmsc_getle16 - * - * Description: - * Get a 16-bit little-endian value reference by the byte pointer - * - ****************************************************************************/ - -#if 0 /* not used */ -static uint16_t usbmsc_getle16(uint8_t *buf) -{ - return ((uint16_t)buf[1] << 8) | ((uint16_t)buf[0]); -} -#endif - -/**************************************************************************** - * Name: usbmsc_getle32 - * - * Description: - * Get a 32-bit little-endian value reference by the byte pointer - * - ****************************************************************************/ - -static uint32_t usbmsc_getle32(uint8_t *buf) -{ - return ((uint32_t)buf[3] << 24) | ((uint32_t)buf[2] << 16) | - ((uint32_t)buf[1] << 8) | ((uint32_t)buf[0]); -} - -/**************************************************************************** - * Name: usbmsc_putle16 - * - * Description: - * Store a 16-bit value in little-endian order to the location specified by - * a byte pointer - * - ****************************************************************************/ - -#if 0 /* not used */ -static void usbmsc_putle16(uint8_t * buf, uint16_t val) -{ - buf[0] = val; - buf[1] = val >> 8; -} -#endif - -/**************************************************************************** - * Name: usbmsc_putle32 - * - * Description: - * Store a 32-bit value in little-endian order to the location specified by - * a byte pointer - * - ****************************************************************************/ - -static void usbmsc_putle32(uint8_t *buf, uint32_t val) -{ - buf[0] = val; - buf[1] = val >> 8; - buf[2] = val >> 16; - buf[3] = val >> 24; -} - -/**************************************************************************** - * SCSI Worker Thread - ****************************************************************************/ - -/**************************************************************************** - * Name: usbmsc_cmdtestunitready - * - * Description: - * Handle the SCSI_CMD_TESTUNITREADY command - * - ****************************************************************************/ - -static inline int usbmsc_cmdtestunitready(FAR struct usbmsc_dev_s *priv) -{ - int ret; - - priv->u.alloclen = 0; - ret = usbmsc_setupcmd(priv, 6, USBMSC_FLAGS_DIRNONE); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdrequestsense - * - * Description: - * Handle the SCSI_CMD_REQUESTSENSE command - * - ****************************************************************************/ - -static inline int usbmsc_cmdrequestsense(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf) -{ - FAR struct scsicmd_requestsense_s *request = (FAR struct scsicmd_requestsense_s *)priv->cdb; - FAR struct scsiresp_fixedsensedata_s *response = (FAR struct scsiresp_fixedsensedata_s *)buf; - FAR struct usbmsc_lun_s *lun; - uint32_t sd; - uint32_t sdinfo; - uint8_t cdblen; - int ret; - - /* Extract the host allocation length */ - - priv->u.alloclen = request->alloclen; - - /* Get the expected length of the command (with hack for MS-Windows 12-byte - * REQUEST SENSE command. - */ - - cdblen = SCSICMD_REQUESTSENSE_SIZEOF; - if (cdblen != priv->cdblen) - { - /* Try MS-Windows REQUEST SENSE with cbw->cdblen == 12 */ - - cdblen = SCSICMD_REQUESTSENSE_MSSIZEOF; - } - - ret = usbmsc_setupcmd(priv, cdblen, - USBMSC_FLAGS_DIRDEVICE2HOST|USBMSC_FLAGS_LUNNOTNEEDED| - USBMSC_FLAGS_UACOKAY|USBMSC_FLAGS_RETAINSENSEDATA); - if (ret == OK) - { - lun = priv->lun; - if (!lun) - { - sd = SCSI_KCQIR_INVALIDLUN; - sdinfo = 0; - } - else - { - /* Get the saved sense data from the LUN structure */ - - sd = lun->sd; - sdinfo = lun->sdinfo; - - /* Discard the sense data */ - - lun->sd = SCSI_KCQ_NOSENSE; - lun->sdinfo = 0; - } - - /* Create the fixed sense data response */ - - memset(response, 0, SCSIRESP_FIXEDSENSEDATA_SIZEOF); - - response->code = SCSIRESP_SENSEDATA_RESPVALID|SCSIRESP_SENSEDATA_CURRENTFIXED; - response->flags = (uint8_t)(sd >> 16); - usbmsc_putbe32(response->info, sdinfo); - response->len = SCSIRESP_FIXEDSENSEDATA_SIZEOF - 7; - response->code2 = (uint8_t)(sd >> 8); - response->qual2 = (uint8_t)sd; - - priv->nreqbytes = SCSIRESP_FIXEDSENSEDATA_SIZEOF; - ret = OK; - } - - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdread6 - * - * Description: - * Handle the SCSI_CMD_READ6 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdread6(FAR struct usbmsc_dev_s *priv) -{ - FAR struct scsicmd_read6_s *read6 = (FAR struct scsicmd_read6_s*)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; - int ret; - - priv->u.xfrlen = (uint16_t)read6->xfrlen; - if (priv->u.xfrlen == 0) - { - priv->u.xfrlen = 256; - } - - ret = usbmsc_setupcmd(priv, SCSICMD_READ6_SIZEOF, USBMSC_FLAGS_DIRDEVICE2HOST|USBMSC_FLAGS_BLOCKXFR); - if (ret == OK) - { - /* Get the Logical Block Address (LBA) from cdb[] as the starting sector */ - - priv->sector = (uint32_t)(read6->mslba & SCSICMD_READ6_MSLBAMASK) << 16 | (uint32_t)usbmsc_getbe16(read6->lslba); - - /* Verify that a block driver has been bound to the LUN */ - - if (!lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ6MEDIANOTPRESENT), 0); - lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - - /* Verify that sector lies in the range supported by the block driver */ - - else if (priv->sector >= lun->nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ6LBARANGE), 0); - lun->sd = SCSI_KCQIR_LBAOUTOFRANGE; - ret = -EINVAL; - } - - /* Looks like we are good to go */ - - else - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDREAD6), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDREAD; - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdwrite6 - * - * Description: - * Handle the SCSI_CMD_WRITE6 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdwrite6(FAR struct usbmsc_dev_s *priv) -{ - FAR struct scsicmd_write6_s *write6 = (FAR struct scsicmd_write6_s *)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; - int ret; - - priv->u.xfrlen = (uint16_t)write6->xfrlen; - if (priv->u.xfrlen == 0) - { - priv->u.xfrlen = 256; - } - - ret = usbmsc_setupcmd(priv, SCSICMD_WRITE6_SIZEOF, USBMSC_FLAGS_DIRHOST2DEVICE|USBMSC_FLAGS_BLOCKXFR); - if (ret == OK) - { - /* Get the Logical Block Address (LBA) from cdb[] as the starting sector */ - - priv->sector = (uint32_t)(write6->mslba & SCSICMD_WRITE6_MSLBAMASK) << 16 | (uint32_t)usbmsc_getbe16(write6->lslba); - - /* Verify that a block driver has been bound to the LUN */ - - if (!lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE6MEDIANOTPRESENT), 0); - lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - - /* Check for attempts to write to a read-only device */ - - else if (lun->readonly) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE6READONLY), 0); - lun->sd = SCSI_KCQWP_COMMANDNOTALLOWED; - ret = -EINVAL; - } - - /* Verify that sector lies in the range supported by the block driver */ - - else if (priv->sector >= lun->nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE6LBARANGE), 0); - lun->sd = SCSI_KCQIR_LBAOUTOFRANGE; - ret = -EINVAL; - } - - /* Looks like we are good to go */ - - else - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDWRITE6), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDWRITE; - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdinquiry - * - * Description: - * Handle SCSI_CMD_INQUIRY command - * - ****************************************************************************/ - -static inline int usbmsc_cmdinquiry(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf) -{ - FAR struct scscicmd_inquiry_s *inquiry = (FAR struct scscicmd_inquiry_s *)priv->cdb; - FAR struct scsiresp_inquiry_s *response = (FAR struct scsiresp_inquiry_s *)buf; - int len; - int ret; - - priv->u.alloclen = usbmsc_getbe16(inquiry->alloclen); - ret = usbmsc_setupcmd(priv, SCSICMD_INQUIRY_SIZEOF, - USBMSC_FLAGS_DIRDEVICE2HOST|USBMSC_FLAGS_LUNNOTNEEDED|USBMSC_FLAGS_UACOKAY); - if (ret == OK) - { - if (!priv->lun) - { - response->qualtype = SCSIRESP_INQUIRYPQ_NOTCAPABLE|SCSIRESP_INQUIRYPD_UNKNOWN; - } - else if ((inquiry->flags != 0) || (inquiry->pagecode != 0)) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INQUIRYFLAGS), 0); - priv->lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - else - { - memset(response, 0, SCSIRESP_INQUIRY_SIZEOF); - priv->nreqbytes = SCSIRESP_INQUIRY_SIZEOF; - -#ifdef CONFIG_USBMSC_REMOVABLE - response->flags1 = SCSIRESP_INQUIRYFLAGS1_RMB; -#endif - response->version = 2; /* SCSI-2 */ - response->flags2 = 2; /* SCSI-2 INQUIRY response data format */ - response->len = SCSIRESP_INQUIRY_SIZEOF - 5; - - /* Strings */ - - memset(response->vendorid, ' ', 8+16+4); - - len = strlen(g_mscvendorstr); - DEBUGASSERT(len <= 8); - memcpy(response->vendorid, g_mscvendorstr, len); - - len = strlen(g_mscproductstr); - DEBUGASSERT(len <= 16); - memcpy(response->productid, g_mscproductstr, len); - - len = strlen(g_mscserialstr); - DEBUGASSERT(len <= 4); - memcpy(response->revision, g_mscserialstr, len); - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdmodeselect6 - * - * Description: - * Handle SCSI_CMD_MODESELECT6 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdmodeselect6(FAR struct usbmsc_dev_s *priv) -{ - FAR struct scsicmd_modeselect6_s *modeselect = (FAR struct scsicmd_modeselect6_s *)priv->cdb; - - priv->u.alloclen = modeselect->plen; - (void)usbmsc_setupcmd(priv, SCSICMD_MODESELECT6_SIZEOF, USBMSC_FLAGS_DIRHOST2DEVICE); - - /* Not supported */ - - priv->lun->sd = SCSI_KCQIR_INVALIDCOMMAND; - return -EINVAL; -} - -/**************************************************************************** - * Name: usbmsc_modepage - * - * Description: - * Common logic for usbmsc_cmdmodesense6() and usbmsc_cmdmodesense10() - * - ****************************************************************************/ - -static int usbmsc_modepage(FAR struct usbmsc_dev_s *priv, FAR uint8_t *buf, - uint8_t pcpgcode, int *mdlen) -{ - FAR struct scsiresp_cachingmodepage_s *cmp = (FAR struct scsiresp_cachingmodepage_s *)buf; - - /* Saving parms not supported */ - - if ((pcpgcode & SCSICMD_MODESENSE_PCMASK) == SCSICMD_MODESENSE_PCSAVED) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_PCSAVED), 0); - priv->lun->sd = SCSI_KCQIR_SAVINGPARMSNOTSUPPORTED; - return -EINVAL; - } - - /* Only the caching mode page is supported: */ - - if ((pcpgcode & SCSICMD_MODESENSE_PGCODEMASK) == SCSIRESP_MODESENSE_PGCCODE_CACHING || - (pcpgcode & SCSICMD_MODESENSE_PGCODEMASK) == SCSIRESP_MODESENSE_PGCCODE_RETURNALL) - { - memset(cmp, 0, 12); - cmp->pgcode = SCSIRESP_MODESENSE_PGCCODE_CACHING; - cmp->len = 10; /* n-2 */ - - /* None of the fields are changeable */ - - if (((pcpgcode & SCSICMD_MODESENSE_PCMASK) != SCSICMD_MODESENSE_PCCHANGEABLE)) - { - cmp->flags1 = SCSIRESP_CACHINGMODEPG_WCE; /* Write cache enable */ - cmp->dpflen[0] = 0xff; /* Disable prefetch transfer length = 0xffffffff */ - cmp->dpflen[1] = 0xff; - cmp->maxpf[0] = 0xff; /* Maximum pre-fetch = 0xffffffff */ - cmp->maxpf[1] = 0xff; - cmp->maxpfc[0] = 0xff; /* Maximum pref-fetch ceiling = 0xffffffff */ - cmp->maxpfc[1] = 0xff; - } - - /* Return the mode data length */ - - *mdlen = 12; /* Only the first 12-bytes of caching mode page sent */ - return OK; - } - else - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_MODEPAGEFLAGS), pcpgcode); - priv->lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - return -EINVAL; - } -} - -/**************************************************************************** - * Name: usbmsc_cmdmodesense6 - * - * Description: - * Handle SCSI_CMD_MODESENSE6 command - * - ****************************************************************************/ - -static int inline usbmsc_cmdmodesense6(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf) -{ - FAR struct scsicmd_modesense6_s *modesense = (FAR struct scsicmd_modesense6_s *)priv->cdb; - FAR struct scsiresp_modeparameterhdr6_s *mph = (FAR struct scsiresp_modeparameterhdr6_s *)buf; - int mdlen; - int ret; - - priv->u.alloclen = modesense->alloclen; - ret = usbmsc_setupcmd(priv, SCSICMD_MODESENSE6_SIZEOF, USBMSC_FLAGS_DIRDEVICE2HOST); - if (ret == OK) - { - if ((modesense->flags & ~SCSICMD_MODESENSE6_DBD) != 0 || modesense->subpgcode != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_MODESENSE6FLAGS), 0); - priv->lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - else - { - /* The response consists of: - * - * (1) A MODESENSE6-specific mode parameter header, - * (2) A variable length list of block descriptors, and - * (3) A variable length list of mode page formats - */ - - mph->type = 0; /* Medium type */ - mph->param = (priv->lun->readonly ? SCSIRESP_MODEPARMHDR_DAPARM_WP : 0x00); - mph->bdlen = 0; /* Block descriptor length */ - - /* There are no block descriptors, only the following mode page: */ - - ret = usbmsc_modepage(priv, &buf[SCSIRESP_MODEPARAMETERHDR6_SIZEOF], modesense->pcpgcode, &mdlen); - if (ret == OK) - { - /* Store the mode data length and return the total message size */ - - mph->mdlen = mdlen - 1; - priv->nreqbytes = mdlen + SCSIRESP_MODEPARAMETERHDR6_SIZEOF; - } - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdstartstopunit - * - * Description: - * Handle SCSI_CMD_STARTSTOPUNIT command - * - ****************************************************************************/ - -static inline int usbmsc_cmdstartstopunit(FAR struct usbmsc_dev_s *priv) -{ - int ret; - - priv->u.alloclen = 0; - ret = usbmsc_setupcmd(priv, SCSICMD_STARTSTOPUNIT_SIZEOF, USBMSC_FLAGS_DIRNONE); - if (ret == OK) - { -#ifndef CONFIG_USBMSC_REMOVABLE - /* This command is not valid if the media is not removable */ - - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_NOTREMOVABLE), 0); - lun->sd = SCSI_KCQIR_INVALIDCOMMAND; - ret = -EINVAL; -#endif - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdpreventmediumremoval - * - * Description: - * Handle SCSI_CMD_PREVENTMEDIAREMOVAL command - * - ****************************************************************************/ - -static inline int usbmsc_cmdpreventmediumremoval(FAR struct usbmsc_dev_s *priv) -{ -#ifdef CONFIG_USBMSC_REMOVABLE - FAR struct scsicmd_preventmediumremoval_s *pmr = (FAR struct scsicmd_preventmediumremoval_s *)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; -#endif - int ret; - - priv->u.alloclen = 0; - ret = usbmsc_setupcmd(priv, SCSICMD_PREVENTMEDIUMREMOVAL_SIZEOF, USBMSC_FLAGS_DIRNONE); - if (ret == OK) - { -#ifndef CONFIG_USBMSC_REMOVABLE - lun->sd = SCSI_KCQIR_INVALIDCOMMAND; - ret = -EINVAL; -#else - if ((pmr->prevent & ~SCSICMD_PREVENTMEDIUMREMOVAL_TRANSPORT) != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_PREVENTMEDIUMREMOVALPREVENT), 0); - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - - lun->locked = pmr->prevent & SCSICMD_PREVENTMEDIUMREMOVAL_TRANSPORT; -#endif - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdreadformatcapacity - * - * Description: - * Handle SCSI_CMD_READFORMATCAPACITIES command (MMC) - * - ****************************************************************************/ - -static inline int usbmsc_cmdreadformatcapacity(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf) -{ - FAR struct scsicmd_readformatcapcacities_s *rfc = (FAR struct scsicmd_readformatcapcacities_s *)priv->cdb; - FAR struct scsiresp_readformatcapacities_s *hdr; - FAR struct usbmsc_lun_s *lun = priv->lun; - int ret; - - priv->u.alloclen = usbmsc_getbe16(rfc->alloclen); - ret = usbmsc_setupcmd(priv, SCSICMD_READFORMATCAPACITIES_SIZEOF, USBMSC_FLAGS_DIRDEVICE2HOST); - if (ret == OK) - { - hdr = (FAR struct scsiresp_readformatcapacities_s *)buf; - memset(hdr, 0, SCSIRESP_READFORMATCAPACITIES_SIZEOF); - hdr->listlen = SCSIRESP_CURRCAPACITYDESC_SIZEOF; - - /* Only the Current/Maximum Capacity Descriptor follows the header */ - - usbmsc_putbe32(hdr->nblocks, lun->nsectors); - hdr->type = SCIRESP_RDFMTCAPACITIES_FORMATED; - usbmsc_putbe24(hdr->blocklen, lun->sectorsize); - priv->nreqbytes = SCSIRESP_READFORMATCAPACITIES_SIZEOF; - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdreadcapacity10 - * - * Description: - * Handle SCSI_CMD_READCAPACITY10 command - * - ****************************************************************************/ - -static int inline usbmsc_cmdreadcapacity10(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf) -{ - FAR struct scsicmd_readcapacity10_s *rcc = (FAR struct scsicmd_readcapacity10_s *)priv->cdb; - FAR struct scsiresp_readcapacity10_s *rcr = (FAR struct scsiresp_readcapacity10_s *)buf; - FAR struct usbmsc_lun_s *lun = priv->lun; - uint32_t lba; - int ret; - - priv->u.alloclen = SCSIRESP_READCAPACITY10_SIZEOF; /* Fake the allocation length */ - ret = usbmsc_setupcmd(priv, SCSICMD_READCAPACITY10_SIZEOF, USBMSC_FLAGS_DIRDEVICE2HOST); - if (ret == OK) - { - /* Check the PMI and LBA fields */ - - lba = usbmsc_getbe32(rcc->lba); - - if (rcc->pmi > 1 || (rcc->pmi == 0 && lba != 0)) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READCAPACITYFLAGS), 0); - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - else - { - usbmsc_putbe32(rcr->lba, lun->nsectors - 1); - usbmsc_putbe32(&buf[4], lun->sectorsize); - priv->nreqbytes = SCSIRESP_READCAPACITY10_SIZEOF; - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdread10 - * - * Description: - * Handle SCSI_CMD_READ10 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdread10(FAR struct usbmsc_dev_s *priv) -{ - struct scsicmd_read10_s *read10 = (struct scsicmd_read10_s*)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; - int ret; - - priv->u.xfrlen = usbmsc_getbe16(read10->xfrlen); - ret = usbmsc_setupcmd(priv, SCSICMD_READ10_SIZEOF, USBMSC_FLAGS_DIRDEVICE2HOST|USBMSC_FLAGS_BLOCKXFR); - if (ret == OK) - { - /* Get the Logical Block Address (LBA) from cdb[] as the starting sector */ - - priv->sector = usbmsc_getbe32(read10->lba); - - /* Verify that we can support this read command */ - - if ((read10->flags & ~(SCSICMD_READ10FLAGS_DPO|SCSICMD_READ10FLAGS_FUA)) != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ10FLAGS), 0); - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - - /* Verify that a block driver has been bound to the LUN */ - - else if (!lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ10MEDIANOTPRESENT), 0); - lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - - /* Verify that LBA lies in the range supported by the block driver */ - - else if (priv->sector >= lun->nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ10LBARANGE), 0); - lun->sd = SCSI_KCQIR_LBAOUTOFRANGE; - ret = -EINVAL; - } - - /* Looks like we are good to go */ - - else - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDREAD10), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDREAD; - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdwrite10 - * - * Description: - * Handle SCSI_CMD_WRITE10 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdwrite10(FAR struct usbmsc_dev_s *priv) -{ - struct scsicmd_write10_s *write10 = (struct scsicmd_write10_s *)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; - int ret; - - priv->u.xfrlen = usbmsc_getbe16(write10->xfrlen); - ret = usbmsc_setupcmd(priv, SCSICMD_WRITE10_SIZEOF, USBMSC_FLAGS_DIRHOST2DEVICE|USBMSC_FLAGS_BLOCKXFR); - if (ret == OK) - { - /* Get the Logical Block Address (LBA) from cdb[] as the starting sector */ - - priv->sector = usbmsc_getbe32(write10->lba); - - /* Verify that we can support this write command */ - - if ((write10->flags & ~(SCSICMD_WRITE10FLAGS_DPO|SCSICMD_WRITE10FLAGS_FUA)) != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE10FLAGS), 0); - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - - /* Verify that a block driver has been bound to the LUN */ - - else if (!lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE10MEDIANOTPRESENT), 0); - lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - - /* Check for attempts to write to a read-only device */ - - else if (lun->readonly) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE10READONLY), 0); - lun->sd = SCSI_KCQWP_COMMANDNOTALLOWED; - ret = -EINVAL; - } - - /* Verify that LBA lies in the range supported by the block driver */ - - else if (priv->sector >= lun->nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE10LBARANGE), 0); - lun->sd = SCSI_KCQIR_LBAOUTOFRANGE; - ret = -EINVAL; - } - - /* Looks like we are good to go */ - - else - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDWRITE10), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDWRITE; - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdverify10 - * - * Description: - * Handle SCSI_CMD_VERIFY10 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdverify10(FAR struct usbmsc_dev_s *priv) -{ - FAR struct scsicmd_verify10_s *verf = (FAR struct scsicmd_verify10_s *)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; - uint32_t lba; - uint16_t blocks; - size_t sector; - ssize_t nread; - int ret; - int i; - - priv->u.alloclen = 0; - ret = usbmsc_setupcmd(priv, SCSICMD_VERIFY10_SIZEOF, USBMSC_FLAGS_DIRNONE); - if (ret == OK) - { - /* Verify the starting and ending LBA */ - - lba = usbmsc_getbe32(verf->lba); - blocks = usbmsc_getbe16(verf->len); - - if ((verf->flags & ~SCSICMD_VERIFY10_DPO) != 0 || verf->groupno != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_VERIFY10FLAGS), 0); - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - else if (blocks == 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_VERIFY10NOBLOCKS), 0); - ret = -EIO; /* No reply */ - } - - /* Verify that a block driver has been bound to the LUN */ - - else if (!lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_VERIFY10MEDIANOTPRESENT), 0); - lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - - /* Verify that LBA lies in the range supported by the block driver */ - - else if (lba >= lun->nsectors || lba + blocks > lun->nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_VERIFY10LBARANGE), 0); - lun->sd = SCSI_KCQIR_LBAOUTOFRANGE; - ret = -EINVAL; - } - else - { - /* Try to read the requested blocks */ - - for (i = 0, sector = lba + lun->startsector; i < blocks; i++, sector++) - { - nread = USBMSC_DRVR_READ(lun, priv->iobuffer, sector, 1); - if (nread < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_VERIFY10READFAIL), i); - lun->sd = SCSI_KCQME_UNRRE1; - lun->sdinfo = sector; - ret = -EIO; - break; - } - } - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdsynchronizecache10 - * - * Description: - * Handle SCSI_CMD_SYNCHCACHE10 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdsynchronizecache10(FAR struct usbmsc_dev_s *priv) -{ - int ret; - - priv->u.alloclen = 0; - - /* Verify that we have the LUN structure and the block driver has been bound */ - - if (!priv->lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SYNCCACHEMEDIANOTPRESENT), 0); - priv->lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - else - { - ret = usbmsc_setupcmd(priv, SCSICMD_SYNCHRONIZECACHE10_SIZEOF, USBMSC_FLAGS_DIRNONE); - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdmodeselect10 - * - * Description: - * Handle SCSI_CMD_MODESELECT10 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdmodeselect10(FAR struct usbmsc_dev_s *priv) -{ - FAR struct scsicmd_modeselect10_s *modeselect = (FAR struct scsicmd_modeselect10_s *)priv->cdb; - - priv->u.alloclen = usbmsc_getbe16(modeselect->parmlen); - (void)usbmsc_setupcmd(priv, SCSICMD_MODESELECT10_SIZEOF, USBMSC_FLAGS_DIRHOST2DEVICE); - - /* Not supported */ - - priv->lun->sd = SCSI_KCQIR_INVALIDCOMMAND; - return -EINVAL; -} - -/**************************************************************************** - * Name: usbmsc_cmdmodesense10 - * - * Description: - * Handle SCSI_CMD_MODESENSE10 command - * - ****************************************************************************/ - -static int inline usbmsc_cmdmodesense10(FAR struct usbmsc_dev_s *priv, - FAR uint8_t *buf) -{ - FAR struct scsicmd_modesense10_s *modesense = (FAR struct scsicmd_modesense10_s *)priv->cdb; - FAR struct scsiresp_modeparameterhdr10_s *mph = (FAR struct scsiresp_modeparameterhdr10_s *)buf; - int mdlen; - int ret; - - priv->u.alloclen = usbmsc_getbe16(modesense->alloclen); - ret = usbmsc_setupcmd(priv, SCSICMD_MODESENSE10_SIZEOF, USBMSC_FLAGS_DIRDEVICE2HOST); - if (ret == OK) - { - if ((modesense->flags & ~SCSICMD_MODESENSE10_DBD) != 0 || modesense->subpgcode != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_MODESENSE10FLAGS), 0); - priv->lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - else - { - /* The response consists of: - * - * (1) A MODESENSE6-specific mode parameter header, - * (2) A variable length list of block descriptors, and - * (3) A variable lengtth list of mode page formats - */ - - memset(mph, 0, SCSIRESP_MODEPARAMETERHDR10_SIZEOF); - mph->param = (priv->lun->readonly ? SCSIRESP_MODEPARMHDR_DAPARM_WP : 0x00); - - /* There are no block descriptors, only the following mode page: */ - - ret = usbmsc_modepage(priv, &buf[SCSIRESP_MODEPARAMETERHDR10_SIZEOF], modesense->pcpgcode, &mdlen); - if (ret == OK) - { - /* Store the mode data length and return the total message size */ - - usbmsc_putbe16(mph->mdlen, mdlen - 2); - priv->nreqbytes = mdlen + SCSIRESP_MODEPARAMETERHDR10_SIZEOF; - } - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdread12 - * - * Description: - * Handle SCSI_CMD_READ12 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdread12(FAR struct usbmsc_dev_s *priv) -{ - struct scsicmd_read12_s *read12 = (struct scsicmd_read12_s*)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; - int ret; - - priv->u.xfrlen = usbmsc_getbe32(read12->xfrlen); - ret = usbmsc_setupcmd(priv, SCSICMD_READ12_SIZEOF, USBMSC_FLAGS_DIRDEVICE2HOST|USBMSC_FLAGS_BLOCKXFR); - if (ret == OK) - { - /* Get the Logical Block Address (LBA) from cdb[] as the starting sector */ - - priv->sector = usbmsc_getbe32(read12->lba); - - /* Verify that we can support this read command */ - - if ((read12->flags & ~(SCSICMD_READ12FLAGS_DPO|SCSICMD_READ12FLAGS_FUA)) != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ12FLAGS), 0); - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - ret = -EINVAL; - } - - /* Verify that a block driver has been bound to the LUN */ - - else if (!lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ12MEDIANOTPRESENT), 0); - lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - - /* Verify that LBA lies in the range supported by the block driver */ - - else if (priv->sector >= lun->nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_READ12LBARANGE), 0); - lun->sd = SCSI_KCQIR_LBAOUTOFRANGE; - ret = -EINVAL; - } - - /* Looks like we are good to go */ - - else - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDREAD12), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDREAD; - } - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdwrite12 - * - * Description: - * Handle SCSI_CMD_WRITE12 command - * - ****************************************************************************/ - -static inline int usbmsc_cmdwrite12(FAR struct usbmsc_dev_s *priv) -{ - struct scsicmd_write12_s *write12 = (struct scsicmd_write12_s *)priv->cdb; - FAR struct usbmsc_lun_s *lun = priv->lun; - int ret; - - priv->u.xfrlen = usbmsc_getbe32(write12->xfrlen); - ret = usbmsc_setupcmd(priv, SCSICMD_WRITE12_SIZEOF, USBMSC_FLAGS_DIRHOST2DEVICE|USBMSC_FLAGS_BLOCKXFR); - if (ret == OK) - { - /* Get the Logical Block Address (LBA) from cdb[] as the starting sector */ - - priv->sector = usbmsc_getbe32(write12->lba); - - /* Verify that we can support this write command */ - - if ((write12->flags & ~(SCSICMD_WRITE12FLAGS_DPO|SCSICMD_WRITE12FLAGS_FUA)) != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE12FLAGS), 0); - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - } - - /* Verify that a block driver has been bound to the LUN */ - - else if (!lun->inode) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE12MEDIANOTPRESENT), 0); - lun->sd = SCSI_KCQNR_MEDIANOTPRESENT; - ret = -EINVAL; - } - - /* Check for attempts to write to a read-only device */ - - else if (lun->readonly) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE12READONLY), 0); - lun->sd = SCSI_KCQWP_COMMANDNOTALLOWED; - } - - /* Verify that LBA lies in the range supported by the block driver */ - - else if (priv->sector >= lun->nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRITE12LBARANGE), 0); - lun->sd = SCSI_KCQIR_LBAOUTOFRANGE; - } - - /* Looks like we are good to go */ - - else - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDWRITE12), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDWRITE; - return OK; - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbmsc_setupcmd - * - * Description: - * Called after each SCSI command is identified in order to perform setup - * and verification operations that are common to all SCSI commands. This - * function performs the following common setup operations: - * - * 1. Determine the direction of the response - * 2. Verify lengths - * 3. Setup and verify the LUN - * - * Includes special logic for INQUIRY and REQUESTSENSE commands - * - ****************************************************************************/ - -static int inline usbmsc_setupcmd(FAR struct usbmsc_dev_s *priv, uint8_t cdblen, uint8_t flags) -{ - FAR struct usbmsc_lun_s *lun = NULL; - uint32_t datlen; - uint8_t dir = flags & USBMSC_FLAGS_DIRMASK; - int ret = OK; - - /* Verify the LUN and set up the current LUN reference in the - * device structure - */ - - if (priv->cbwlun < priv->nluns) - { - /* LUN number is valid in a valid range, but the LUN is not necessarily - * bound to a block driver. That will be checked as necessary in each - * individual command. - */ - - lun = &priv->luntab[priv->cbwlun]; - priv->lun = lun; - } - - /* Only a few commands may specify unsupported LUNs */ - - else if ((flags & USBMSC_FLAGS_LUNNOTNEEDED) == 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDBADLUN), priv->cbwlun); - ret = -EINVAL; - } - - /* Extract the direction and data transfer length */ - - dir = flags & USBMSC_FLAGS_DIRMASK; /* Expected data direction */ - datlen = 0; - if ((flags & USBMSC_FLAGS_BLOCKXFR) == 0) - { - /* Non-block transfer. Data length: Host allocation to receive data - * (only for device-to-host transfers. At present, alloclen is set - * to zero for all host-to-device, non-block transfers. - */ - - datlen = priv->u.alloclen; - } - else if (lun) - { - /* Block transfer: Calculate the total size of all sectors to be transferred */ - - datlen = priv->u.alloclen * lun->sectorsize; - } - - /* Check the data direction. This was set up at the end of the - * IDLE state when the CBW was parsed, but if there is no data, - * then the direction is none. - */ - - if (datlen == 0) - { - /* No data.. then direction is none */ - - dir = USBMSC_FLAGS_DIRNONE; - } - - /* Compare the expected data length in the command to the data length - * in the CBW. - */ - - else if (priv->cbwlen < datlen) - { - /* Clip to the length in the CBW and declare a phase error */ - - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_PHASEERROR1), priv->cdb[0]); - if ((flags & USBMSC_FLAGS_BLOCKXFR) != 0) - { - priv->u.alloclen = priv->cbwlen; - } - else - { - priv->u.xfrlen = priv->cbwlen / lun->sectorsize; - } - - priv->phaseerror = 1; - } - - /* Initialize the residue */ - - priv->residue = priv->cbwlen; - - /* Conflicting data directions is a phase error */ - - if (priv->cbwdir != dir && datlen > 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_PHASEERROR2), priv->cdb[0]); - priv->phaseerror = 1; - ret = -EINVAL; - } - - /* Compare the length of data in the cdb[] with the expected length - * of the command. - */ - - if (cdblen != priv->cdblen) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_PHASEERROR3), priv->cdb[0]); - priv->phaseerror = 1; - ret = -EINVAL; - } - - if (lun) - { - /* Retain the sense data for the REQUEST SENSE command */ - - if ((flags & USBMSC_FLAGS_RETAINSENSEDATA) == 0) - { - /* Discard the sense data */ - - lun->sd = SCSI_KCQ_NOSENSE; - lun->sdinfo = 0; - } - - /* If a unit attention condition exists, then only a restricted set of - * commands is permitted. - */ - - if (lun->uad != SCSI_KCQ_NOSENSE && (flags & USBMSC_FLAGS_UACOKAY) != 0) - { - /* Command not permitted */ - - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDUNEVIOLATION), priv->cbwlun); - lun->sd = lun->uad; - lun->uad = SCSI_KCQ_NOSENSE; - ret = -EINVAL; - } - } - - /* The final, 1-byte field of every SCSI command is the Control field which - * must be zero - */ - - if (priv->cdb[cdblen-1] != 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SCSICMDCONTROL), 0); - if (lun) - { - lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA; - } - ret = -EINVAL; - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_idlestate - * - * Description: - * Called from the worker thread in the USBMSC_STATE_IDLE state. Checks - * for the receipt of a bulk CBW. - * - * Returned value: - * If no new, valid CBW is available, this function returns a negated errno. - * Otherwise, when a new CBW is successfully parsed, this function sets - * priv->thstate to USBMSC_STATE_CMDPARSE and returns OK. - * - ****************************************************************************/ - -static int usbmsc_idlestate(FAR struct usbmsc_dev_s *priv) -{ - FAR struct usbmsc_req_s *privreq; - FAR struct usbdev_req_s *req; - FAR struct usbmsc_cbw_s *cbw; - irqstate_t flags; - int ret = -EINVAL; - - /* Take a request from the rdreqlist */ - - flags = irqsave(); - privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->rdreqlist); - irqrestore(flags); - - /* Has anything been received? If not, just return an error. - * This will cause us to remain in the IDLE state. When a USB request is - * received, the worker thread will be awakened in the USBMSC_STATE_IDLE - * and we will be called again. - */ - - if (!privreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_IDLERDREQLISTEMPTY), 0); - return -ENOMEM; - } - - req = privreq->req; - cbw = (FAR struct usbmsc_cbw_s *)req->buf; - - /* Handle the CBW */ - - usbmsc_dumpdata("SCSCI CBW", (uint8_t*)cbw, USBMSC_CBW_SIZEOF - USBMSC_MAXCDBLEN); - usbmsc_dumpdata(" CDB", cbw->cdb, MIN(cbw->cdblen, USBMSC_MAXCDBLEN)); - - /* Check for properly formatted CBW? */ - - if (req->xfrd != USBMSC_CBW_SIZEOF || - cbw->signature[0] != 'U' || - cbw->signature[1] != 'S' || - cbw->signature[2] != 'B' || - cbw->signature[3] != 'C') - { - /* CBS BAD: Stall the bulk endpoints. If the CBW is bad we must stall the - * bulk IN endpoint and either (1) stall the bulk OUT endpoint, or - * (2) discard data from the endpoint. - */ - - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INVALIDCBWSIGNATURE), 0); - EP_STALL(priv->epbulkout); - EP_STALL(priv->epbulkin); - } - - /* Is the CBW meaningful? */ - - else if (cbw->lun >= priv->nluns || (cbw->flags & ~USBMSC_CBWFLAG_IN) != 0 || - cbw->cdblen < 6 || cbw->cdblen > USBMSC_MAXCDBLEN) - { - /* CBS BAD: Stall the bulk endpoints. If the CBW is bad we must stall the - * bulk IN endpoint and either (1) stall the bulk OUT endpoint, or - * (2) discard data from the endpoint. - */ - - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INVALIDCBWCONTENT), 0); - EP_STALL(priv->epbulkout); - EP_STALL(priv->epbulkin); - } - - /* Save the information from the CBW */ - - else - { - /* Extract the CDB and copy the whole CBD[] for later use */ - - priv->cdblen = cbw->cdblen; - memcpy(priv->cdb, cbw->cdb, priv->cdblen); - - /* Extract the data direction */ - - if ((cbw->flags & USBMSC_CBWFLAG_IN) != 0) - { - /* IN: Device-to-host */ - - priv->cbwdir = USBMSC_FLAGS_DIRDEVICE2HOST; - } - else - { - /* OUT: Host-to-device */ - - priv->cbwdir = USBMSC_FLAGS_DIRHOST2DEVICE; - } - - /* Get the max size of the data response */ - - priv->cbwlen = usbmsc_getle32(cbw->datlen); - if (priv->cbwlen == 0) - { - /* No length? Then no direction either */ - - priv->cbwdir = USBMSC_FLAGS_DIRNONE; - } - - /* Extract and save the LUN index and TAG value */ - - priv->cbwlun = cbw->lun; - priv->cbwtag = usbmsc_getle32(cbw->tag); - - /* Return the read request to the bulk out endpoint for re-filling */ - - req = privreq->req; - req->len = CONFIG_USBMSC_BULKOUTREQLEN; - req->priv = privreq; - req->callback = usbmsc_rdcomplete; - - /* Change to the CMDPARSE state and return success */ - - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_IDLECMDPARSE), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDPARSE; - ret = OK; - } - - /* In any event, return the request to be refilled */ - - if (EP_SUBMIT(priv->epbulkout, req) != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_IDLERDSUBMIT), (uint16_t)-ret); - } - - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdparsestate - * - * Description: - * Called from the worker thread in the USBMSC_STATE_CMDPARSE state. - * This state is entered when usbmsc_idlestate obtains a valid CBW - * containing SCSI commands. This function processes those SCSI commands. - * - * Returned value: - * If no write request is available or certain other errors occur, this - * function returns a negated errno and stays in the USBMSC_STATE_CMDPARSE - * state. Otherwise, when the new CBW is successfully process, this - * function sets priv->thstate to one of USBMSC_STATE_CMDREAD, - * USBMSC_STATE_CMDWRITE, or USBMSC_STATE_CMDFINISH and returns OK. - * - ****************************************************************************/ - -static int usbmsc_cmdparsestate(FAR struct usbmsc_dev_s *priv) -{ - FAR struct usbmsc_req_s *privreq; - FAR uint8_t *buf; - int ret = -EINVAL; - - usbmsc_dumpdata("SCSCI CDB", priv->cdb, priv->cdblen); - - /* Check if there is a request in the wrreqlist that we will be able to - * use for data or status. - */ - - privreq = (FAR struct usbmsc_req_s *)sq_peek(&priv->wrreqlist); - - /* If there no request structures available, then just return an error. - * This will cause us to remain in the CMDPARSE state. When a request is - * returned, the worker thread will be awakened in the USBMSC_STATE_CMDPARSE - * and we will be called again. - */ - - if (!privreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDPARSEWRREQLISTEMPTY), 0); - return -ENOMEM; - } - - DEBUGASSERT(privreq->req && privreq->req->buf); - buf = privreq->req->buf; - - /* Assume that no errors will be encountered */ - - priv->phaseerror = 0; - priv->shortpacket = 0; - - /* No data is buffered */ - - priv->nsectbytes = 0; - priv->nreqbytes = 0; - - /* Get exclusive access to the block driver */ - - pthread_mutex_lock(&priv->mutex); - switch (priv->cdb[0]) - { - case SCSI_CMD_TESTUNITREADY: /* 0x00 Mandatory */ - ret = usbmsc_cmdtestunitready(priv); - break; - - /* case SCSI_CMD_REZEROUNIT: * 0x01 Obsolete - * * 0x02 Vendor-specific */ - - case SCSI_CMD_REQUESTSENSE: /* 0x03 Mandatory */ - ret = usbmsc_cmdrequestsense(priv, buf); - break; - - /* case SCSI_CMD_FORMAT_UNIT: * 0x04 Mandatory, but not implemented - * * 0x05 Vendor specific - * * 0x06 Vendor specific - * case SCSI_CMD_REASSIGNBLOCKS: * 0x07 Optional */ - - case SCSI_CMD_READ6: /* 0x08 Mandatory */ - ret = usbmsc_cmdread6(priv); - break; - - /* * 0x09 Vendor specific */ - - case SCSI_CMD_WRITE6: /* 0x0a Optional */ - ret = usbmsc_cmdwrite6(priv); - break; - - /* case SCSI_CMD_SEEK6: * 0x0b Obsolete - * * 0x0c-0x10 Vendor specific - * case SCSI_CMD_SPACE6: * 0x11 Vendor specific */ - - case SCSI_CMD_INQUIRY: /* 0x12 Mandatory */ - ret = usbmsc_cmdinquiry(priv, buf); - break; - - /* * 0x13-0x14 Vendor specific */ - - case SCSI_CMD_MODESELECT6: /* 0x15 Optional */ - ret = usbmsc_cmdmodeselect6(priv); - break; - - /* case SCSI_CMD_RESERVE6: * 0x16 Obsolete - * case SCSI_CMD_RELEASE6: * 0x17 Obsolete - * case SCSI_CMD_COPY: * 0x18 Obsolete - * * 0x19 Vendor specific */ - - case SCSI_CMD_MODESENSE6: /* 0x1a Optional */ - ret = usbmsc_cmdmodesense6(priv, buf); - break; - - case SCSI_CMD_STARTSTOPUNIT: /* 0x1b Optional */ - ret = usbmsc_cmdstartstopunit(priv); - break; - - /* case SCSI_CMD_RECEIVEDIAGNOSTICRESULTS: * 0x1c Optional - * case SCSI_CMD_SENDDIAGNOSTIC: * 0x1d Mandatory, but not implemented */ - - case SCSI_CMD_PREVENTMEDIAREMOVAL: /* 0x1e Optional */ - ret = usbmsc_cmdpreventmediumremoval(priv); - break; - - /* * 0x20-22 Vendor specific */ - case SCSI_CMD_READFORMATCAPACITIES: /* 0x23 Vendor-specific (defined in MMC spec) */ - ret = usbmsc_cmdreadformatcapacity(priv, buf); - break; - /* * 0x24 Vendor specific */ - - case SCSI_CMD_READCAPACITY10: /* 0x25 Mandatory */ - ret = usbmsc_cmdreadcapacity10(priv, buf); - break; - - /* * 0x26-27 Vendor specific */ - case SCSI_CMD_READ10: /* 0x28 Mandatory */ - ret = usbmsc_cmdread10(priv); - break; - - /* * 0x29 Vendor specific */ - - case SCSI_CMD_WRITE10: /* 0x2a Optional */ - ret = usbmsc_cmdwrite10(priv); - break; - - /* case SCSI_CMD_SEEK10: * 0x2b Obsolete - * * 0x2c-2d Vendor specific - * case SCSI_CMD_WRITEANDVERIFY: * 0x2e Optional */ - - case SCSI_CMD_VERIFY10: /* 0x2f Optional, but needed my MS Windows */ - ret = usbmsc_cmdverify10(priv); - break; - - /* case SCSI_CMD_SEARCHDATAHIGH: * 0x30 Obsolete - * case SCSI_CMD_SEARCHDATAEQUAL: * 0x31 Obsolete - * case SCSI_CMD_SEARCHDATALOW: * 0x32 Obsolete - * case SCSI_CMD_SETLIMITS10: * 0x33 Obsolete - * case SCSI_CMD_PREFETCH10: * 0x34 Optional */ - - case SCSI_CMD_SYNCHCACHE10: /* 0x35 Optional */ - ret = usbmsc_cmdsynchronizecache10(priv); - break; - - /* case SCSI_CMD_LOCKCACHE: * 0x36 Obsolete - * case SCSI_CMD_READDEFECTDATA10: * 0x37 Optional - * case SCSI_CMD_COMPARE: * 0x39 Obsolete - * case SCSI_CMD_COPYANDVERIFY: * 0x3a Obsolete - * case SCSI_CMD_WRITEBUFFER: * 0x3b Optional - * case SCSI_CMD_READBUFFER: * 0x3c Optional - * case SCSI_CMD_READLONG10: * 0x3e Optional - * case SCSI_CMD_WRITELONG10: * 0x3f Optional - * case SCSI_CMD_CHANGEDEFINITION: * 0x40 Obsolete - * case SCSI_CMD_WRITESAME10: * 0x41 Optional - * case SCSI_CMD_LOGSELECT: * 0x4c Optional - * case SCSI_CMD_LOGSENSE: * 0x4d Optional - * case SCSI_CMD_XDWRITE10: * 0x50 Optional - * case SCSI_CMD_XPWRITE10: * 0x51 Optional - * case SCSI_CMD_XDREAD10: * 0x52 Optional */ - - case SCSI_CMD_MODESELECT10: /* 0x55 Optional */ - ret = usbmsc_cmdmodeselect10(priv); - break; - - /* case SCSI_CMD_RESERVE10: * 0x56 Obsolete - * case SCSI_CMD_RELEASE10: * 0x57 Obsolete */ - - case SCSI_CMD_MODESENSE10: /* 0x5a Optional */ - ret = usbmsc_cmdmodesense10(priv, buf); - break; - - /* case SCSI_CMD_PERSISTENTRESERVEIN: * 0x5e Optional - * case SCSI_CMD_PERSISTENTRESERVEOUT: * 0x5f Optional - * case SCSI_CMD_32: * 0x7f Optional - * case SCSI_CMD_XDWRITEEXTENDED: * 0x80 Obsolete - * case SCSI_CMD_REBUILD: * 0x81 Obsolete - * case SCSI_CMD_REGENERATE: * 0x82 Obsolete - * case SCSI_CMD_EXTENDEDCOPY: * 0x83 Optional - * case SCSI_CMD_COPYRESULTS: * 0x84 Optional - * case SCSI_CMD_ACCESSCONTROLIN: * 0x86 Optional - * case SCSI_CMD_ACCESSCONTROLOUT: * 0x87 Optional - * case SCSI_CMD_READ16: * 0x88 Optional - * case SCSI_CMD_WRITE16: * 0x8a Optional - * case SCSI_CMD_READATTRIBUTE: * 0x8c Optional - * case SCSI_CMD_WRITEATTRIBUTE: * 0x8d Optional - * case SCSI_CMD_WRITEANDVERIFY16: * 0x8e Optional - * case SCSI_CMD_SYNCHCACHE16: * 0x91 Optional - * case SCSI_CMD_LOCKUNLOCKACACHE: * 0x92 Optional - * case SCSI_CMD_WRITESAME16: * 0x93 Optional - * case SCSI_CMD_READCAPACITY16: * 0x9e Optional - * case SCSI_CMD_READLONG16: * 0x9e Optional - * case SCSI_CMD_WRITELONG16 * 0x9f Optional - * case SCSI_CMD_REPORTLUNS: * 0xa0 Mandatory, but not implemented - * case SCSI_CMD_MAINTENANCEIN: * 0xa3 Optional (SCCS==0) - * case SCSI_CMD_MAINTENANCEOUT: * 0xa4 Optional (SCCS==0) - * case SCSI_CMD_MOVEMEDIUM: * 0xa5 ? - * case SCSI_CMD_MOVEMEDIUMATTACHED: * 0xa7 Optional (MCHNGR==0) */ - - case SCSI_CMD_READ12: /* 0xa8 Optional */ - ret = usbmsc_cmdread12(priv); - break; - - case SCSI_CMD_WRITE12: /* 0xaa Optional */ - ret = usbmsc_cmdwrite12(priv); - break; - - /* case SCSI_CMD_READMEDIASERIALNUMBER: * 0xab Optional - * case SCSI_CMD_WRITEANDVERIFY12: * 0xae Optional - * case SCSI_CMD_VERIFY12: * 0xaf Optional - * case SCSI_CMD_SETLIMITS12 * 0xb3 Obsolete - * case SCSI_CMD_READELEMENTSTATUS: * 0xb4 Optional (MCHNGR==0) - * case SCSI_CMD_READDEFECTDATA12: * 0xb7 Optional - * case SCSI_CMD_REDUNDANCYGROUPIN: * 0xba Optional - * case SCSI_CMD_REDUNDANCYGROUPOUT: * 0xbb Optional - * case SCSI_CMD_SPAREIN: * 0xbc Optional (SCCS==0) - * case SCSI_CMD_SPAREOUT: * 0xbd Optional (SCCS==0) - * case SCSI_CMD_VOLUMESETIN: * 0xbe Optional (SCCS==0) - * case SCSI_CMD_VOLUMESETOUT: * 0xbe Optional (SCCS==0) - * * 0xc0-0xff Vendor specific */ - - default: - priv->u.alloclen = 0; - if (ret == OK) - { - priv->lun->sd = SCSI_KCQIR_INVALIDCOMMAND; - ret = -EINVAL; - } - break; - } - pthread_mutex_unlock(&priv->mutex); - - /* Is a response required? (Not for read6/10/12 and write6/10/12). */ - - if (priv->thstate == USBMSC_STATE_CMDPARSE) - { - /* All commands come through this path (EXCEPT read6/10/12 and write6/10/12). - * For all other commands, the following setup is expected for the response - * based on data direction: - * - * For direction NONE: - * 1. priv->u.alloclen == 0 - * 2. priv->nreqbytes == 0 - * - * For direction = device-to-host: - * 1. priv->u.alloclen == allocation length; space set aside by the - * host to receive the device data. The size of the response - * cannot exceed this value. - * 2. response data is in the request currently at the head of - * the priv->wrreqlist queue. priv->nreqbytes is set to the length - * of data in the response. - * - * For direction host-to-device - * At present, there are no supported commands that should have host-to-device - * transfers (except write6/10/12 and that command logic does not take this - * path. The 'residue' is left at the full host-to-device data size. - * - * For all: - * ret set to <0 if an error occurred in parsing the commands. - */ - - /* For from device-to-hose operations, the residue is the expected size - * (the initial value of 'residue') minus the amount actually returned - * in the response: - */ - - if (priv->cbwdir == USBMSC_FLAGS_DIRDEVICE2HOST) - { - /* The number of bytes in the response cannot exceed the host - * 'allocation length' in the command. - */ - - if (priv->nreqbytes > priv->u.alloclen) - { - priv->nreqbytes = priv->u.alloclen; - } - - /* The residue is then the number of bytes that were not sent */ - - priv->residue -= priv->nreqbytes; - } - - /* On return, we need the following: - * - * 1. Setup for CMDFINISH state if appropriate - * 2. priv->thstate set to either CMDPARSE if no buffer was available or - * CMDFINISH to send the response - * 3. Return OK to continue; <0 to wait for the next event - */ - - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDFINISH), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDFINISH; - ret = OK; - } - return ret; -} - -/**************************************************************************** - * Name: usbmsc_cmdreadstate - * - * Description: - * Called from the worker thread in the USBMSC_STATE_CMDREAD state. - * The USBMSC_STATE_CMDREAD state is entered when usbmsc_cmdparsestate - * obtains a valid SCSI read command. This state is really a continuation - * of the USBMSC_STATE_CMDPARSE state that handles extended SCSI read - * command handling. - * - * Returned value: - * If no USBDEV write request is available or certain other errors occur, this - * function returns a negated errno and stays in the USBMSC_STATE_CMDREAD - * state. Otherwise, when the new SCSI read command is fully processed, - * this function sets priv->thstate to USBMSC_STATE_CMDFINISH and returns OK. - * - * State variables: - * xfrlen - holds the number of sectors read to be read. - * sector - holds the sector number of the next sector to be read - * nsectbytes - holds the number of bytes buffered for the current sector - * nreqbytes - holds the number of bytes currently buffered in the request - * at the head of the wrreqlist. - * - ****************************************************************************/ - -static int usbmsc_cmdreadstate(FAR struct usbmsc_dev_s *priv) -{ - FAR struct usbmsc_lun_s *lun = priv->lun; - FAR struct usbmsc_req_s *privreq; - FAR struct usbdev_req_s *req; - irqstate_t flags; - ssize_t nread; - uint8_t *src; - uint8_t *dest; - int nbytes; - int ret; - - /* Loop transferring data until either (1) all of the data has been - * transferred, or (2) we have used up all of the write requests that we have - * available. - */ - - while (priv->u.xfrlen > 0 || priv->nsectbytes > 0) - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDREAD), priv->u.xfrlen); - - /* Is the I/O buffer empty? */ - - if (priv->nsectbytes <= 0) - { - /* Yes.. read the next sector */ - - nread = USBMSC_DRVR_READ(lun, priv->iobuffer, priv->sector, 1); - if (nread < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDREADREADFAIL), -nread); - lun->sd = SCSI_KCQME_UNRRE1; - lun->sdinfo = priv->sector; - break; - } - - priv->nsectbytes = lun->sectorsize; - priv->u.xfrlen--; - priv->sector++; - } - - /* Check if there is a request in the wrreqlist that we will be able to - * use for data transfer. - */ - - privreq = (FAR struct usbmsc_req_s *)sq_peek(&priv->wrreqlist); - - /* If there no request structures available, then just return an error. - * This will cause us to remain in the CMDREAD state. When a request is - * returned, the worker thread will be awakened in the USBMSC_STATE_CMDREAD - * and we will be called again. - */ - - if (!privreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDREADWRRQEMPTY), 0); - priv->nreqbytes = 0; - return -ENOMEM; - } - req = privreq->req; - - /* Transfer all of the data that will (1) fit into the request buffer, OR (2) - * all of the data available in the sector buffer. - */ - - src = &priv->iobuffer[lun->sectorsize - priv->nsectbytes]; - dest = &req->buf[priv->nreqbytes]; - - nbytes = MIN(CONFIG_USBMSC_BULKINREQLEN - priv->nreqbytes, priv->nsectbytes); - - /* Copy the data from the sector buffer to the USB request and update counts */ - - memcpy(dest, src, nbytes); - priv->nreqbytes += nbytes; - priv->nsectbytes -= nbytes; - - /* If (1) the request buffer is full OR (2) this is the final request full of data, - * then submit the request - */ - - if (priv->nreqbytes >= CONFIG_USBMSC_BULKINREQLEN || - (priv->u.xfrlen <= 0 && priv->nsectbytes <= 0)) - { - /* Remove the request that we just filled from wrreqlist (we've already checked - * that is it not NULL - */ - - flags = irqsave(); - privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); - irqrestore(flags); - - /* And submit the request to the bulk IN endpoint */ - - req->len = priv->nreqbytes; - req->priv = privreq; - req->callback = usbmsc_wrcomplete; - req->flags = 0; - - ret = EP_SUBMIT(priv->epbulkin, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDREADSUBMIT), (uint16_t)-ret); - lun->sd = SCSI_KCQME_UNRRE1; - lun->sdinfo = priv->sector; - break; - } - - /* Assume success... residue should probably really be decremented in - * wrcomplete when we know that the transfer completed successfully. - */ - - priv->residue -= priv->nreqbytes; - priv->nreqbytes = 0; - } - } - - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDREADCMDFINISH), priv->u.xfrlen); - priv->thstate = USBMSC_STATE_CMDFINISH; - return OK; -} - -/**************************************************************************** - * Name: usbmsc_cmdwritestate - * - * Description: - * Called from the worker thread in the USBMSC_STATE_CMDWRITE state. - * The USBMSC_STATE_CMDWRITE state is entered when usbmsc_cmdparsestate - * obtains a valid SCSI write command. This state is really a continuation - * of the USBMSC_STATE_CMDPARSE state that handles extended SCSI write - * command handling. - * - * Returned value: - * If no USBDEV write request is available or certain other errors occur, this - * function returns a negated errno and stays in the USBMSC_STATE_CMDWRITE - * state. Otherwise, when the new SCSI write command is fully processed, - * this function sets priv->thstate to USBMSC_STATE_CMDFINISH and returns OK. - * - * State variables: - * xfrlen - holds the number of sectors read to be written. - * sector - holds the sector number of the next sector to write - * nsectbytes - holds the number of bytes buffered for the current sector - * nreqbytes - holds the number of untransferred bytes currently in the - * request at the head of the rdreqlist. - * - ****************************************************************************/ - -static int usbmsc_cmdwritestate(FAR struct usbmsc_dev_s *priv) -{ - FAR struct usbmsc_lun_s *lun = priv->lun; - FAR struct usbmsc_req_s *privreq; - FAR struct usbdev_req_s *req; - ssize_t nwritten; - uint16_t xfrd; - uint8_t *src; - uint8_t *dest; - int nbytes; - int ret; - - /* Loop transferring data until either (1) all of the data has been - * transferred, or (2) we have written all of the data in the available - * read requests. - */ - - while (priv->u.xfrlen > 0) - { - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDWRITE), priv->u.xfrlen); - - /* Check if there is a request in the rdreqlist containing additional - * data to be written. - */ - - privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->rdreqlist); - - /* If there no request data available, then just return an error. - * This will cause us to remain in the CMDWRITE state. When a filled request is - * received, the worker thread will be awakened in the USBMSC_STATE_CMDWRITE - * and we will be called again. - */ - - if (!privreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDWRITERDRQEMPTY), 0); - priv->nreqbytes = 0; - return -ENOMEM; - } - - req = privreq->req; - xfrd = req->xfrd; - priv->nreqbytes = xfrd; - - /* Now loop until all of the data in the read request has been tranferred - * to the block driver OR all of the request data has been transferred. - */ - - while (priv->nreqbytes > 0 && priv->u.xfrlen > 0) - { - /* Copy the data received in the read request into the sector I/O buffer */ - - src = &req->buf[xfrd - priv->nreqbytes]; - dest = &priv->iobuffer[priv->nsectbytes]; - - nbytes = MIN(lun->sectorsize - priv->nsectbytes, priv->nreqbytes); - - /* Copy the data from the sector buffer to the USB request and update counts */ - - memcpy(dest, src, nbytes); - priv->nsectbytes += nbytes; - priv->nreqbytes -= nbytes; - - /* Is the I/O buffer full? */ - - if (priv->nsectbytes >= lun->sectorsize) - { - /* Yes.. Write the next sector */ - - nwritten = USBMSC_DRVR_WRITE(lun, priv->iobuffer, priv->sector, 1); - if (nwritten < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDWRITEWRITEFAIL), -nwritten); - lun->sd = SCSI_KCQME_WRITEFAULTAUTOREALLOCFAILED; - lun->sdinfo = priv->sector; - goto errout; - } - - priv->nsectbytes = 0; - priv->residue -= lun->sectorsize; - priv->u.xfrlen--; - priv->sector++; - } - } - - /* In either case, we are finished with this read request and can return it - * to the endpoint. Then we will go back to the top of the top and attempt - * to get the next read request. - */ - - req->len = CONFIG_USBMSC_BULKOUTREQLEN; - req->priv = privreq; - req->callback = usbmsc_rdcomplete; - - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDWRITERDSUBMIT), (uint16_t)-ret); - } - - /* Did the host decide to stop early? */ - - if (xfrd != CONFIG_USBMSC_BULKOUTREQLEN) - { - priv->shortpacket = 1; - goto errout; - } - } - -errout: - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDWRITECMDFINISH), priv->u.xfrlen); - priv->thstate = USBMSC_STATE_CMDFINISH; - return OK; -} - -/**************************************************************************** - * Name: usbmsc_cmdfinishstate - * - * Description: - * Called from the worker thread in the USBMSC_STATE_CMDFINISH state. - * The USBMSC_STATE_CMDFINISH state is entered when processing of a - * command has finished but before status has been returned. - * - * Returned value: - * If no USBDEV write request is available or certain other errors occur, this - * function returns a negated errno and stays in the USBMSC_STATE_CMDFINISH - * state. Otherwise, when the command is fully processed, this function - * sets priv->thstate to USBMSC_STATE_CMDSTATUS and returns OK. - * - ****************************************************************************/ - -static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv) -{ - FAR struct usbmsc_req_s *privreq; - irqstate_t flags; - int ret = OK; - - /* Check if there is a request in the wrreqlist that we will be able to - * use for data transfer. - */ - - privreq = (FAR struct usbmsc_req_s *)sq_peek(&priv->wrreqlist); - - /* If there no request structures available, then just return an error. - * This will cause us to remain in the CMDREAD state. When a request is - * returned, the worker thread will be awakened in the USBMSC_STATE_CMDREAD - * and we will be called again. - */ - - if (!privreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINISHRQEMPTY), 0); - return -ENOMEM; - } - - /* Finish the final stages of the reply */ - - switch (priv->cbwdir) - { - /* Device-to-host: All but the last data buffer has been sent */ - - case USBMSC_FLAGS_DIRDEVICE2HOST: - if (priv->cbwlen > 0) - { - /* On most commands (the exception is outgoing, write commands), - * the data has not not yet been sent. - */ - - if (priv->nreqbytes > 0) - { - struct usbdev_req_s *req; - - /* Take a request from the wrreqlist (we've already checked - * that is it not NULL) - */ - - flags = irqsave(); - privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); - irqrestore(flags); - - /* Send the write request */ - - req = privreq->req; - req->len = priv->nreqbytes; - req->callback = usbmsc_wrcomplete; - req->priv = privreq; - req->flags = USBDEV_REQFLAGS_NULLPKT; - - ret = EP_SUBMIT(priv->epbulkin, privreq->req); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINISHSUBMIT), (uint16_t)-ret); - } - } - - /* Stall the BULK In endpoint if there is a residue */ - - if (priv->residue > 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINISHRESIDUE), (uint16_t)priv->residue); - -#ifdef CONFIG_USBMSC_RACEWAR - /* (See description of the workaround at the top of the file). - * First, wait for the transfer to complete, then stall the endpoint - */ - - usleep (100000); - (void)EP_STALL(priv->epbulkin); - - /* now wait for stall to go away .... */ - - usleep (100000); -#else - (void)EP_STALL(priv->epbulkin); -#endif - } - } - break; - - /* Host-to-device: We have processed all we want of the host data. */ - - case USBMSC_FLAGS_DIRHOST2DEVICE: - if (priv->residue > 0) - { - /* Did the host stop sending unexpectedly early? */ - - flags = irqsave(); - if (priv->shortpacket) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINISHSHORTPKT), (uint16_t)priv->residue); - } - - /* Unprocessed incoming data: STALL and cancel requests. */ - - else - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINSHSUBMIT), (uint16_t)priv->residue); - EP_STALL(priv->epbulkout); - } - - priv->theventset |= USBMSC_EVENT_ABORTBULKOUT; - irqrestore(flags); - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINSHDIR), priv->cbwdir); - case USBMSC_FLAGS_DIRNONE: /* Nothing to send */ - break; - } - - /* Return to the IDLE state */ - - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDFINISHCMDSTATUS), 0); - priv->thstate = USBMSC_STATE_CMDSTATUS; - return OK; -} - -/**************************************************************************** - * Name: usbmsc_cmdstatusstate - * - * Description: - * Called from the worker thread in the USBMSC_STATE_CMDSTATUS state. - * That state is after a CBW has been fully processed. This function sends - * the concluding CSW. - * - * Returned value: - * If no write request is available or certain other errors occur, this - * function returns a negated errno and stays in the USBMSC_STATE_CMDSTATUS - * state. Otherwise, when the SCSI statis is successfully returned, this - * function sets priv->thstate to USBMSC_STATE_IDLE and returns OK. - * - ****************************************************************************/ - -static int usbmsc_cmdstatusstate(FAR struct usbmsc_dev_s *priv) -{ - FAR struct usbmsc_lun_s *lun = priv->lun; - FAR struct usbmsc_req_s *privreq; - FAR struct usbdev_req_s *req; - FAR struct usbmsc_csw_s *csw; - irqstate_t flags; - uint32_t sd; - uint8_t status = USBMSC_CSWSTATUS_PASS; - int ret; - - /* Take a request from the wrreqlist */ - - flags = irqsave(); - privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); - irqrestore(flags); - - /* If there no request structures available, then just return an error. - * This will cause us to remain in the CMDSTATUS status. When a request is - * returned, the worker thread will be awakened in the USBMSC_STATE_CMDSTATUS - * and we will be called again. - */ - - if (!privreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDSTATUSRDREQLISTEMPTY), 0); - return -ENOMEM; - } - - req = privreq->req; - csw = (struct usbmsc_csw_s*)req->buf; - - /* Extract the sense data from the LUN structure */ - - if (lun) - { - sd = lun->sd; - } - else - { - sd = SCSI_KCQIR_INVALIDLUN; - } - - /* Determine the CSW status: PASS, PHASEERROR, or FAIL */ - - if (priv->phaseerror) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SNDPHERROR), 0); - status = USBMSC_CSWSTATUS_PHASEERROR; - sd = SCSI_KCQIR_INVALIDCOMMAND; - } - else if (sd != SCSI_KCQ_NOSENSE) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SNDCSWFAIL), 0); - status = USBMSC_CSWSTATUS_FAIL; - } - - /* Format and submit the CSW */ - - csw->signature[0] = 'U'; - csw->signature[1] = 'S'; - csw->signature[2] = 'B'; - csw->signature[3] = 'S'; - usbmsc_putle32(csw->tag, priv->cbwtag); - usbmsc_putle32(csw->residue, priv->residue); - csw->status = status; - - usbmsc_dumpdata("SCSCI CSW", (uint8_t*)csw, USBMSC_CSW_SIZEOF); - - req->len = USBMSC_CSW_SIZEOF; - req->callback = usbmsc_wrcomplete; - req->priv = privreq; - req->flags = USBDEV_REQFLAGS_NULLPKT; - - ret = EP_SUBMIT(priv->epbulkin, req); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SNDSTATUSSUBMIT), (uint16_t)-ret); - flags = irqsave(); - (void)sq_addlast((sq_entry_t*)privreq, &priv->wrreqlist); - irqrestore(flags); - } - - /* Return to the IDLE state */ - - usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDSTATUSIDLE), 0); - priv->thstate = USBMSC_STATE_IDLE; - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbmsc_workerthread - * - * Description: - * This is the main function of the USB storage worker thread. It loops - * until USB-related events occur, then processes those events accordingly - * - ****************************************************************************/ - -void *usbmsc_workerthread(void *arg) -{ - struct usbmsc_dev_s *priv = (struct usbmsc_dev_s *)arg; - irqstate_t flags; - uint16_t eventset; - int ret; - - /* This thread is started before the USB storage class is fully initialized. - * wait here until we are told to begin. Start in the NOTINITIALIZED state - */ - - pthread_mutex_lock(&priv->mutex); - priv->thstate = USBMSC_STATE_STARTED; - while ((priv->theventset & USBMSC_EVENT_READY) != 0 && - (priv->theventset & USBMSC_EVENT_TERMINATEREQUEST) != 0) - { - pthread_cond_wait(&priv->cond, &priv->mutex); - } - - /* Transition to the INITIALIZED/IDLE state */ - - priv->thstate = USBMSC_STATE_IDLE; - eventset = priv->theventset; - priv->theventset = USBMSC_EVENT_NOEVENTS; - pthread_mutex_unlock(&priv->mutex); - - /* Then loop until we are asked to terminate */ - - while ((eventset & USBMSC_EVENT_TERMINATEREQUEST) == 0) - { - /* Wait for some interesting event. Note that we must both take the - * lock (to eliminate race conditions with other threads) and disable - * interrupts (to eliminate race conditions with USB interrupt handling. - */ - - pthread_mutex_lock(&priv->mutex); - flags = irqsave(); - if (priv->theventset == USBMSC_EVENT_NOEVENTS) - { - pthread_cond_wait(&priv->cond, &priv->mutex); - } - - /* Sample any events before re-enabling interrupts. Any events that - * occur after re-enabling interrupts will have to be handled in the - * next time through the loop. - */ - - eventset = priv->theventset; - priv->theventset = USBMSC_EVENT_NOEVENTS; - pthread_mutex_unlock(&priv->mutex); - - /* Were we awakened by some event that requires immediate action? - * - * - The USBMSC_EVENT_DISCONNECT is signalled from the disconnect method - * after all transfers have been stopped, when the host is disconnected. - * - * - The CUSBMSC_EVENT_RESET is signalled when the bulk-storage-specific - * USBMSC_REQ_MSRESET EP0 setup received. We must stop the current - * operation and reinialize state. - * - * - The USBMSC_EVENT_CFGCHANGE is signaled when the EP0 setup logic - * receives a valid USB_REQ_SETCONFIGURATION request - * - * - The USBMSC_EVENT_IFCHANGE is signaled when the EP0 setup logic - * receives a valid USB_REQ_SETINTERFACE request - * - * - The USBMSC_EVENT_ABORTBULKOUT event is signalled by the CMDFINISH - * logic when there is a residue after processing a host-to-device - * transfer. We need to discard all incoming request. - * - * All other events are just wakeup calls and are intended only - * drive the state machine. - */ - - if ((eventset & (USBMSC_EVENT_DISCONNECT|USBMSC_EVENT_RESET|USBMSC_EVENT_CFGCHANGE| - USBMSC_EVENT_IFCHANGE|USBMSC_EVENT_ABORTBULKOUT)) != 0) - { - /* These events require that the current configuration be reset */ - - if ((eventset & USBMSC_EVENT_IFCHANGE) != 0) - { - usbmsc_resetconfig(priv); - } - - /* These events require that a new configuration be established */ - - if ((eventset & (USBMSC_EVENT_CFGCHANGE|USBMSC_EVENT_IFCHANGE)) != 0) - { - usbmsc_setconfig(priv, priv->thvalue); - } - - /* These events required that we send a deferred EP0 setup response */ - - if ((eventset & (USBMSC_EVENT_RESET|USBMSC_EVENT_CFGCHANGE|USBMSC_EVENT_IFCHANGE)) != 0) - { - usbmsc_deferredresponse(priv, false); - } - - /* For all of these events... terminate any transactions in progress */ - - priv->thstate = USBMSC_STATE_IDLE; - } - irqrestore(flags); - - /* Loop processing each SCSI command state. Each state handling - * function will do the following: - * - * - If it must block for an event, it will return a negated errno value - * - If it completes the processing for that state, it will (1) set - * the next appropriate state value and (2) return OK. - * - * So the following will loop until we must block for an event in - * a particular state. When we are awakened by an event (above) we - * will resume processing in the same state. - */ - - do - { - switch (priv->thstate) - { - case USBMSC_STATE_IDLE: /* Started and waiting for commands */ - ret = usbmsc_idlestate(priv); - break; - - case USBMSC_STATE_CMDPARSE: /* Parsing the received a command */ - ret = usbmsc_cmdparsestate(priv); - break; - - case USBMSC_STATE_CMDREAD: /* Continuing to process a SCSI read command */ - ret = usbmsc_cmdreadstate(priv); - break; - - case USBMSC_STATE_CMDWRITE: /* Continuing to process a SCSI write command */ - ret = usbmsc_cmdwritestate(priv); - break; - - case USBMSC_STATE_CMDFINISH: /* Finish command processing */ - ret = usbmsc_cmdfinishstate(priv); - break; - - case USBMSC_STATE_CMDSTATUS: /* Processing the status phase of a command */ - ret = usbmsc_cmdstatusstate(priv); - break; - - case USBMSC_STATE_NOTSTARTED: /* Thread has not yet been started */ - case USBMSC_STATE_STARTED: /* Started, but is not yet initialized */ - case USBMSC_STATE_TERMINATED: /* Thread has exitted */ - default: - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INVALIDSTATE), priv->thstate); - priv->thstate = USBMSC_STATE_IDLE; - ret = OK; - break; - } - } - while (ret == OK); - } - - /* Transition to the TERMINATED state and exit */ - - priv->thstate = USBMSC_STATE_TERMINATED; - return NULL; -} diff --git a/nuttx/drivers/usbhost/Kconfig b/nuttx/drivers/usbhost/Kconfig deleted file mode 100644 index 531e94442..000000000 --- a/nuttx/drivers/usbhost/Kconfig +++ /dev/null @@ -1,114 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config USBHOST_NPREALLOC - int "Number of pre-allocated class instances" - default 4 - ---help--- - Number of pre-allocated class instances - -config USBHOST_BULK_DISABLE - bool "Disable bulk endpoint support" - default n - ---help--- - On some architectures, selecting this setting will reduce driver size - by disabling bulk endpoint support - -config USBHOST_INT_DISABLE - bool "Disable interrupt endpoint support" - default n - ---help--- - On some architectures, selecting this setting will reduce driver size - by disabling interrupt endpoint support - -config USBHOST_ISOC_DISABLE - bool "Disable isochronous endpoint support" - default n - ---help--- - On some architectures, selecting this setting will reduce driver size - by disabling isochronous endpoint support - -config USBHOST_MSC - bool "Mass Storage Class Support" - default n - depends on !BULK_DISABLE - ---help--- - Enable support for the keyboard class driver. This also depends on - NFILE_DESCRIPTORS > 0 && SCHED_WORKQUEUE=y - -config USBHOST_HIDKBD - bool "HID Keyboard Class Support" - default n - depends on !INT_DISABLE - ---help--- - Enable support for the keyboard class driver. This also depends on - SCHED_WORKQUEUE && !DISABLE_SIGNALS - -if USBHOST_HIDKBD -config HIDKBD_POLLUSEC - int "Keyboard Poll Rate (MSEC)" - default 100000 - ---help--- - Device poll rate in microseconds. Default: 100,000 microseconds. - -config HIDKBD_DEFPRIO - int "Polling Thread Priority" - default 50 - ---help--- - Priority of the polling thread. Default: 50. - -config HIDKBD_STACKSIZE - int "Polling thread stack size" - default 1024 - ---help--- - Stack size for polling thread. Default: 1024 - -config HIDKBD_BUFSIZE - int "Scancode Buffer Size" - default 64 - ---help--- - Scancode buffer size. Default: 64. - -config HIDKBD_NPOLLWAITERS - int "Max Number of Waiters for Poll Event" - default 2 - depends on !DISABLE_POLL - ---help--- - If the poll() method is enabled, this defines the maximum number - of threads that can be waiting for keyboard events. Default: 2. - -config HIDKBD_RAWSCANCODES - bool "Use Raw Scan Codes" - default n - ---help--- - If set to y no conversions will be made on the raw keyboard scan - codes. This option is useful during testing. Default: ASCII conversion. - -config HIDKBD_ENCODED - bool "Enocode Special Keys" - default n - depends on !HIDKBD_RAWSCANCODES && LIB_KBDCODEC - ---help--- - Encode special key press events in the user buffer. In this case, - the user end must decode the encoded special key values using the - interfaces defined in include/nuttx/input/kbd_codec.h. These - special keys include such things as up/down arrows, home and end - keys, etc. If this not defined, only 7-bit print-able and control - ASCII characters will be provided to the user. - -config HIDKBD_ALLSCANCODES - bool "Use All Scancodes" - default n - ---help--- - If set to y all 231 possible scancodes will be converted to - something. Default: 104 key US keyboard. - -config HIDKBD_NODEBOUNCE - bool "Disable Debounce" - default n - ---help--- - If set to y normal debouncing is disabled. Default: - Debounce enabled (No repeat keys). -endif diff --git a/nuttx/drivers/usbhost/Make.defs b/nuttx/drivers/usbhost/Make.defs deleted file mode 100644 index ebb522695..000000000 --- a/nuttx/drivers/usbhost/Make.defs +++ /dev/null @@ -1,57 +0,0 @@ -############################################################################ -# drivers/usbhost/Make.defs -# -# Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -CSRCS += hid_parser.c - -ifeq ($(CONFIG_USBHOST),y) - -# Include built-in USB host driver logic - -CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c -CSRCS += usbhost_enumerate.c usbhost_storage.c usbhost_hidkbd.c - -# Include add-on USB host driver logic (see misc/drivers) - -ifeq ($(CONFIG_NET),y) - RTL8187_CSRC := ${shell if [ -f usbhost$(DELIM)rtl8187x.c ]; then echo "rtl8187x.c"; fi} - CSRCS += $(RTL8187_CSRC) -endif -endif - -# Include USB host driver build logic - -DEPPATH += --dep-path usbhost -VPATH += :usbhost -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)usbhost} diff --git a/nuttx/drivers/usbhost/hid_parser.c b/nuttx/drivers/usbhost/hid_parser.c deleted file mode 100644 index a0ca6066b..000000000 --- a/nuttx/drivers/usbhost/hid_parser.c +++ /dev/null @@ -1,529 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/hid_parser.c - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * - * Adapted from the LUFA Library: - * - * Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) - * dean [at] fourwalledcubicle [dot] com, www.lufa-lib.org - * - * Permission to use, copy, modify, distribute, and sell this - * software and its documentation for any purpose is hereby granted - * without fee, provided that the above copyright notice appear in - * all copies and that both that the copyright notice and this - * permission notice and warranty disclaimer appear in supporting - * documentation, and that the name of the author not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * The author disclaim all warranties with regard to this - * software, including all implied warranties of merchantability - * and fitness. In no event shall the author be liable for any - * special, indirect or consequential damages or any damages - * whatsoever resulting from loss of use, data or profits, whether - * in an action of contract, negligence or other tortious action, - * arising out of or in connection with the use or performance of - * this software. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct hid_state_s -{ - struct hid_rptitem_attributes_s attrib; - uint8_t rptcount; - uint8_t id; -}; - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: hid_parsereport - * - * Description: - * Function to process a given HID report returned from an attached device, - * and store it into a given struct hid_rptinfo_s structure. - * - * Input Parameters: - * report Buffer containing the device's HID report table. - * rptlen Size in bytes of the HID report table. - * filter Callback function to decide if an item should be retained - * rptinfo Pointer to a struct hid_rptinfo_s instance for the parser output. - * - * Returned Value: - * Zero on success, otherwise a negated errno value. - ****************************************************************************/ - -int hid_parsereport(FAR const uint8_t *report, int rptlen, - hid_rptfilter_t filter, FAR struct hid_rptinfo_s *rptinfo) -{ - struct hid_state_s state[CONFIG_HID_STATEDEPTH]; - struct hid_state_s *currstate = &state[0]; - struct hid_collectionpath_s *collectionpath = NULL; - struct hid_rptsizeinfo_s *rptidinfo = &rptinfo->rptsize[0]; - uint16_t usage[CONFIG_HID_USAGEDEPTH]; - uint8_t nusage = 0; - struct hid_range_s usage_range = { 0, 0 }; - int i; - - DEBUGASSERT(report && filter && rptinfo); - - memset(rptinfo, 0x00, sizeof(struct hid_rptinfo_s)); - memset(currstate, 0x00, sizeof(struct hid_state_s)); - memset(rptidinfo, 0x00, sizeof(struct hid_rptsizeinfo_s)); - - rptinfo->nreports = 1; - - while (rptlen > 0) - { - uint8_t item = *report; - uint32_t data = 0; - - report++; - rptlen--; - - switch (item & USBHID_RPTITEM_SIZE_MASK) - { - case USBHID_RPTITEM_SIZE_4: /* 4 bytes of little endian data follow */ - data = (uint32_t)(*report++); - data |= (uint32_t)(*report++) << 8; - data |= (uint32_t)(*report++) << 16; - data |= (uint32_t)(*report++) << 24; - rptlen -= 4; - break; - - case USBHID_RPTITEM_SIZE_2: /* 2 bytes of little endian data follow */ - data = (uint32_t)(*report++); - data |= (uint32_t)(*report++) << 8; - rptlen -= 2; - break; - - case USBHID_RPTITEM_SIZE_1: /* 1 byte of data follows */ - data = (uint32_t)(*report++); - rptlen -= 1; - break; - - case USBHID_RPTITEM_SIZE_0: /* No data follows */ - default: - break; - } - - switch (item & ~USBHID_RPTITEM_SIZE_MASK) - { - case USBHID_GLOBAL_PUSH_PREFIX: - if (currstate == &state[CONFIG_HID_STATEDEPTH - 1]) - { - return -E2BIG; - } - - memcpy((currstate + 1), - currstate, sizeof(struct hid_rptitem_s)); - - currstate++; - break; - - case USBHID_GLOBAL_POP_PREFIX: - if (currstate == &state[0]) - { - return -EINVAL; /* Pop without push? */ - } - - currstate--; - break; - - case USBHID_GLOBAL_USAGEPAGE_PREFIX: - if ((item & USBHID_RPTITEM_SIZE_MASK) == USBHID_RPTITEM_SIZE_4) - { - currstate->attrib.usage.page = (data >> 16); - } - - currstate->attrib.usage.page = data; - break; - - case USBHID_GLOBAL_LOGICALMIN_PREFIX: - currstate->attrib.logical.min = data; - break; - - case USBHID_GLOBAL_LOGICALMAX_PREFIX: - currstate->attrib.logical.max = data; - break; - - case USBHID_GLOBAL_PHYSICALMIN_PREFIX: - currstate->attrib.physical.min = data; - break; - - case USBHID_GLOBAL_PHYSMICALAX_PREFIX: - currstate->attrib.physical.max = data; - break; - - case USBHID_GLOBAL_UNITEXP_PREFIX: - currstate->attrib.unit.exponent = data; - break; - - case USBHID_GLOBAL_UNIT_PREFIX: - currstate->attrib.unit.type = data; - break; - - case USBHID_GLOBAL_REPORTSIZE_PREFIX: - currstate->attrib.bitsize = data; - break; - - case USBHID_GLOBAL_REPORTCOUNT_PREFIX: - currstate->rptcount = data; - break; - - case USBHID_GLOBAL_REPORTID_PREFIX: - currstate->id = data; - - if (rptinfo->haverptid) - { - rptidinfo = NULL; - - for (i = 0; i < rptinfo->nreports; i++) - { - if (rptinfo->rptsize[i].id == currstate->id) - { - rptidinfo = &rptinfo->rptsize[i]; - break; - } - } - - if (rptidinfo == NULL) - { - if (rptinfo->nreports == CONFIG_HID_MAXIDS) - { - return -EINVAL; - } - - rptidinfo = &rptinfo->rptsize[rptinfo->nreports++]; - memset(rptidinfo, 0x00, sizeof(struct hid_rptsizeinfo_s)); - } - } - - rptinfo->haverptid = true; - - rptidinfo->id = currstate->id; - break; - - case USBHID_LOCAL_USAGE_PREFIX: - if (nusage == CONFIG_HID_USAGEDEPTH) - { - return -E2BIG; - } - - usage[nusage++] = data; - break; - - case USBHID_LOCAL_USAGEMIN_PREFIX: - usage_range.min = data; - break; - - case USBHID_LOCAL_USAGEMAX_PREFIX: - usage_range.max = data; - break; - - case USBHID_MAIN_COLLECTION_PREFIX: - if (collectionpath == NULL) - { - collectionpath = &rptinfo->collectionpaths[0]; - } - else - { - struct hid_collectionpath_s *ParentCollectionPath = collectionpath; - - collectionpath = &rptinfo->collectionpaths[1]; - - while (collectionpath->parent != NULL) - { - if (collectionpath == &rptinfo->collectionpaths[CONFIG_HID_MAXCOLLECTIONS - 1]) - { - return -EINVAL; - } - - collectionpath++; - } - - collectionpath->parent = ParentCollectionPath; - } - - collectionpath->type = data; - collectionpath->usage.page = currstate->attrib.usage.page; - - if (nusage) - { - collectionpath->usage.usage = usage[0]; - - for (i = 0; i < nusage; i++) - usage[i] = usage[i + 1]; - - nusage--; - } - else if (usage_range.min <= usage_range.max) - { - collectionpath->usage.usage = usage_range.min++; - } - - break; - - case USBHID_MAIN_ENDCOLLECTION_PREFIX: - if (collectionpath == NULL) - { - return -EINVAL; - } - - collectionpath = collectionpath->parent; - break; - - case USBHID_MAIN_INPUT_PREFIX: - case USBHID_MAIN_OUTPUT_PREFIX: - case USBHID_MAIN_FEATURE_PREFIX: - { - int itemno; - for (itemno = 0; itemno < currstate->rptcount; itemno++) - { - struct hid_rptitem_s newitem; - uint8_t tag; - - memcpy(&newitem.attrib, &currstate->attrib, - sizeof(struct hid_rptitem_attributes_s)); - - newitem.flags = data; - newitem.collectionpath = collectionpath; - newitem.id = currstate->id; - - if (nusage) - { - newitem.attrib.usage.usage = usage[0]; - - for (i = 0; i < nusage; i++) - { - usage[i] = usage[i + 1]; - } - nusage--; - } - else if (usage_range.min <= usage_range.max) - { - newitem.attrib.usage.usage = usage_range.min++; - } - - tag = (item & ~USBHID_RPTITEM_SIZE_MASK); - if (tag == USBHID_MAIN_INPUT_PREFIX) - { - newitem.type = HID_REPORT_ITEM_IN; - } - else if (tag == USBHID_MAIN_OUTPUT_PREFIX) - { - newitem.type = HID_REPORT_ITEM_OUT; - } - else - { - newitem.type = HID_REPORT_ITEM_FEATURE; - } - - newitem.bitoffset = rptidinfo->size[newitem.type]; - rptidinfo->size[newitem.type] += currstate->attrib.bitsize; - - /* Accumulate the maximum report size */ - - if (rptinfo->maxrptsize < newitem.bitoffset) - { - rptinfo->maxrptsize = newitem.bitoffset; - } - - if ((data & USBHID_MAIN_CONSTANT) == 0 && filter(&newitem)) - { - if (rptinfo->nitems == CONFIG_HID_MAXITEMS) - { - return -EINVAL; - } - - memcpy(&rptinfo->items[rptinfo->nitems], - &newitem, sizeof(struct hid_rptitem_s)); - - rptinfo->nitems++; - } - } - } - break; - } - - if ((item & USBHID_RPTITEM_TYPE_MASK) == USBHID_RPTITEM_TYPE_MAIN) - { - usage_range.min = 0; - usage_range.max = 0; - nusage = 0; - } - } - - if (!(rptinfo->nitems)) - { - return -ENOENT; - } - - return OK; -} - -/**************************************************************************** - * Name: hid_getitem - * - * Description: - * Extracts the given report item's value out of the given HID report and - * places it into the value member of the report item's struct hid_rptitem_s - * structure. - * - * When called on a report with an item that exists in that report, this - * copies the report item's Value to it's previous element for easy - * checking to see if an item's value has changed before processing a - * report. If the given item does not exist in the report, the function - * does not modify the report item's data. - * - * Input Parameters - * report Buffer containing an IN or FEATURE report from an attached - * device. - * item Pointer to the report item of interest in a struct hid_rptinfo_s - * item array. - * - * Returned Value: - * Zero on success, otherwise a negated errno value. - * - ****************************************************************************/ - -int hid_getitem(FAR const uint8_t *report, FAR struct hid_rptitem_s *item) -{ - uint16_t remaining = item->attrib.bitsize; - uint16_t offset = item->bitoffset; - uint32_t mask = (1 << 0); - - if (item->id) - { - if (item->id != report[0]) - { - return -ENOENT; - } - - report++; - } - - item->previous = item->value; - item->value = 0; - - while (remaining--) - { - if (report[offset >> 3] & (1 << (offset & 7))) - { - item->value |= mask; - } - - offset++; - mask <<= 1; - } - - return OK; -} - -/**************************************************************************** - * Name: hid_putitem - * - * Desription: - * Retrieves the given report item's value out of the Value member of the - * report item's struct hid_rptitem_s structure and places it into the correct - * position in the HID report buffer. The report buffer is assumed to have - * the appropriate bits cleared before calling this function (i.e., the - * buffer should be explicitly cleared before report values are added). - * - * When called, this copies the report item's Value element to it's - * previous element for easy checking to see if an item's value has - * changed before sending a report. - * - * If the device has multiple HID reports, the first byte in the report is - * set to the report ID of the given item. - * - * Input Parameters: - * report Buffer holding the current OUT or FEATURE report data. - * item Pointer to the report item of interest in a struct hid_rptinfo_s - * item array. - * - ****************************************************************************/ - -#if 0 /* Not needed by host */ -void hid_putitem(FAR uint8_t *report, struct hid_rptitem_s *item) -{ - uint16_t remaining = item->attrib.bitsize; - uint16_t offset = item->bitoffset; - uint32_t mask = (1 << 0); - - if (item->id) - { - report[0] = item->id; - report++; - } - - item->previous = item->value; - - while (remaining--) - { - if (item->value & (1 << (offset & 7))) - { - report[offset >> 3] |= mask; - } - - offset++; - mask <<= 1; - } -} -#endif - -/**************************************************************************** - * Name: hid_reportsize - * - * Description: - * Retrieves the size of a given HID report in bytes from it's Report ID. - * - * InputParameters: - * rptinfo Pointer to a struct hid_rptinfo_s instance containing the parser output. - * id Report ID of the report whose size is to be retrieved. - * rpttype Type of the report whose size is to be determined, a valued from the - * HID_ReportItemTypes_t enum. - * - * Size of the report in bytes, or 0 if the report does not exist. - * - ****************************************************************************/ - -size_t hid_reportsize(FAR struct hid_rptinfo_s *rptinfo, uint8_t id, uint8_t rpttype) -{ - int i; - for (i = 0; i < CONFIG_HID_MAXIDS; i++) - { - size_t size = rptinfo->rptsize[i].size[rpttype]; - - if (rptinfo->rptsize[i].id == id) - { - return ((size >> 3) + ((size & 0x07) ? 1 : 0)); - } - } - - return 0; -} diff --git a/nuttx/drivers/usbhost/usbhost_enumerate.c b/nuttx/drivers/usbhost/usbhost_enumerate.c deleted file mode 100644 index 26b93bf36..000000000 --- a/nuttx/drivers/usbhost/usbhost_enumerate.c +++ /dev/null @@ -1,518 +0,0 @@ -/******************************************************************************* - * drivers/usbhost/usbhost_enumerate.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - *******************************************************************************/ - -/******************************************************************************* - * Included Files - *******************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/******************************************************************************* - * Definitions - *******************************************************************************/ - -/******************************************************************************* - * Private Types - *******************************************************************************/ - -/******************************************************************************* - * Private Function Prototypes - *******************************************************************************/ - -static inline uint16_t usbhost_getle16(const uint8_t *val); -static void usbhost_putle16(uint8_t *dest, uint16_t val); - -static inline int usbhost_devdesc(const struct usb_devdesc_s *devdesc, - struct usbhost_id_s *id); -static inline int usbhost_configdesc(const uint8_t *configdesc, int desclen, - struct usbhost_id_s *id); -static inline int usbhost_classbind(FAR struct usbhost_driver_s *drvr, - const uint8_t *configdesc, int desclen, - struct usbhost_id_s *id, uint8_t funcaddr, - FAR struct usbhost_class_s **class); - -/******************************************************************************* - * Private Data - *******************************************************************************/ - -/******************************************************************************* - * Public Data - *******************************************************************************/ - -/******************************************************************************* - * Private Functions - *******************************************************************************/ - -/**************************************************************************** - * Name: usbhost_getle16 - * - * Description: - * Get a (possibly unaligned) 16-bit little endian value. - * - *******************************************************************************/ - -static inline uint16_t usbhost_getle16(const uint8_t *val) -{ - return (uint16_t)val[1] << 8 | (uint16_t)val[0]; -} - -/**************************************************************************** - * Name: usbhost_putle16 - * - * Description: - * Put a (possibly unaligned) 16-bit little endian value. - * - *******************************************************************************/ - -static void usbhost_putle16(uint8_t *dest, uint16_t val) -{ - dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */ - dest[1] = val >> 8; -} - -/******************************************************************************* - * Name: usbhost_devdesc - * - * Description: - * A configuration descriptor has been obtained from the device. Find the - * ID information for the class that supports this device. - * - *******************************************************************************/ - -static inline int usbhost_devdesc(FAR const struct usb_devdesc_s *devdesc, - FAR struct usbhost_id_s *id) -{ - /* Clear the ID info */ - - memset(id, 0, sizeof(struct usbhost_id_s)); - - /* Pick off the class ID info */ - - id->base = devdesc->classid; - id->subclass = devdesc->subclass; - id->proto = devdesc->protocol; - - /* Pick off the VID and PID as well (for vendor specfic devices) */ - - id->vid = usbhost_getle16(devdesc->vendor); - id->pid = usbhost_getle16(devdesc->product); - - uvdbg("class:%d subclass:%04x protocol:%04x vid:%d pid:%d\n", - id->base, id->subclass, id->proto, id->vid, id->pid); - return OK; -} - -/******************************************************************************* - * Name: usbhost_configdesc - * - * Description: - * A configuration descriptor has been obtained from the device. Find the - * ID information for the class that supports this device. - * - *******************************************************************************/ - -static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen, - struct usbhost_id_s *id) -{ - struct usb_cfgdesc_s *cfgdesc; - struct usb_ifdesc_s *ifdesc; - int remaining; - - DEBUGASSERT(configdesc != NULL && cfglen >= USB_SIZEOF_CFGDESC); - - /* Verify that we were passed a configuration descriptor */ - - cfgdesc = (struct usb_cfgdesc_s *)configdesc; - uvdbg("cfg len:%d total len:%d\n", cfgdesc->len, cfglen); - - if (cfgdesc->type != USB_DESC_TYPE_CONFIG) - { - return -EINVAL; - } - - /* Skip to the next entry descriptor */ - - configdesc += cfgdesc->len; - remaining = cfglen - cfgdesc->len; - - /* Loop where there are more dscriptors to examine */ - - memset(id, 0, sizeof(FAR struct usb_desc_s)); - while (remaining >= sizeof(struct usb_desc_s)) - { - /* What is the next descriptor? Is it an interface descriptor? */ - - ifdesc = (struct usb_ifdesc_s *)configdesc; - if (ifdesc->type == USB_DESC_TYPE_INTERFACE) - { - /* Yes, extract the class information from the interface descriptor. - * Typically these values are zero meaning that the "real" ID - * information resides in the device descriptor. - */ - - DEBUGASSERT(remaining >= sizeof(struct usb_ifdesc_s)); - id->base = ifdesc->classid; - id->subclass = ifdesc->subclass; - id->proto = ifdesc->protocol; - uvdbg("class:%d subclass:%d protocol:%d\n", - id->base, id->subclass, id->proto); - return OK; - } - - /* Increment the address of the next descriptor */ - - configdesc += ifdesc->len; - remaining -= ifdesc->len; - } - - return -ENOENT; -} - -/******************************************************************************* - * Name: usbhost_classbind - * - * Description: - * A configuration descriptor has been obtained from the device. Try to - * bind this configuration descriptor with a supported class. - * - *******************************************************************************/ - -static inline int usbhost_classbind(FAR struct usbhost_driver_s *drvr, - const uint8_t *configdesc, int desclen, - struct usbhost_id_s *id, uint8_t funcaddr, - FAR struct usbhost_class_s **class) -{ - FAR struct usbhost_class_s *devclass; - const struct usbhost_registry_s *reg; - int ret = -EINVAL; - - /* Is there is a class implementation registered to support this device. */ - - reg = usbhost_findclass(id); - uvdbg("usbhost_findclass: %p\n", reg); - if (reg) - { - /* Yes.. there is a class for this device. Get an instance of - * its interface. - */ - - ret = -ENOMEM; - devclass = CLASS_CREATE(reg, drvr, id); - uvdbg("CLASS_CREATE: %p\n", devclass); - if (devclass) - { - /* Then bind the newly instantiated class instance */ - - ret = CLASS_CONNECT(devclass, configdesc, desclen, funcaddr); - if (ret != OK) - { - /* On failures, call the class disconnect method which - * should then free the allocated devclass instance. - */ - - udbg("CLASS_CONNECT failed: %d\n", ret); - CLASS_DISCONNECTED(devclass); - } - else - { - *class = devclass; - } - } - } - - uvdbg("Returning: %d\n", ret); - return ret; -} - -/******************************************************************************* - * Public Functions - *******************************************************************************/ - -/******************************************************************************* - * Name: usbhost_enumerate - * - * Description: - * Enumerate the connected device. As part of this enumeration process, - * the driver will (1) get the device's configuration descriptor, (2) - * extract the class ID info from the configuration descriptor, (3) call - * usbhost_findclass() to find the class that supports this device, (4) - * call the create() method on the struct usbhost_registry_s interface - * to get a class instance, and finally (5) call the configdesc() method - * of the struct usbhost_class_s interface. After that, the class is in - * charge of the sequence of operations. - * - * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * class - If the class driver for the device is successful located - * and bound to the driver, the allocated class instance is returned into - * this caller-provided memory location. - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * Assumptions: - * - Only a single class bound to a single device is supported. - * - Called from a single thread so no mutual exclusion is required. - * - Never called from an interrupt handler. - * - *******************************************************************************/ - -int usbhost_enumerate(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, - FAR struct usbhost_class_s **class) -{ - struct usb_ctrlreq_s *ctrlreq; - struct usbhost_id_s id; - size_t maxlen; - unsigned int cfglen; - uint8_t maxpacketsize; - uint8_t *buffer; - int ret; - - DEBUGASSERT(drvr && class); - - /* Allocate descriptor buffers for use in this function. We will need two: - * One for the request and one for the data buffer. - */ - - ret = DRVR_ALLOC(drvr, (FAR uint8_t **)&ctrlreq, &maxlen); - if (ret != OK) - { - udbg("DRVR_ALLOC failed: %d\n", ret); - return ret; - } - - ret = DRVR_ALLOC(drvr, &buffer, &maxlen); - if (ret != OK) - { - udbg("DRVR_ALLOC failed: %d\n", ret); - goto errout; - } - - /* Set max pkt size = 8 */ - - DRVR_EP0CONFIGURE(drvr, 0, 8); - - /* Read first 8 bytes of the device descriptor */ - - ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE; - ctrlreq->req = USB_REQ_GETDESCRIPTOR; - usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8)); - usbhost_putle16(ctrlreq->index, 0); - usbhost_putle16(ctrlreq->len, 8); - - ret = DRVR_CTRLIN(drvr, ctrlreq, buffer); - if (ret != OK) - { - udbg("ERROR: GETDESCRIPTOR/DEVICE, DRVR_CTRLIN returned %d\n", ret); - goto errout; - } - - /* Extract the correct max packetsize from the device descriptor */ - - maxpacketsize = ((struct usb_devdesc_s *)buffer)->mxpacketsize; - uvdbg("maxpacksetsize: %d\n", maxpacketsize); - - /* And reconfigure EP0 */ - - DRVR_EP0CONFIGURE(drvr, 0, maxpacketsize); - - /* Now read the full device descriptor */ - - ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE; - ctrlreq->req = USB_REQ_GETDESCRIPTOR; - usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8)); - usbhost_putle16(ctrlreq->index, 0); - usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC); - - ret = DRVR_CTRLIN(drvr, ctrlreq, buffer); - if (ret != OK) - { - udbg("ERROR: GETDESCRIPTOR/DEVICE, DRVR_CTRLIN returned %d\n", ret); - goto errout; - } - - /* Get class identification information from the device descriptor. Most - * devices set this to USB_CLASS_PER_INTERFACE (zero) and provide the - * identification informatino in the interface descriptor(s). That allows - * a device to support multiple, different classes. - */ - - (void)usbhost_devdesc((struct usb_devdesc_s *)buffer, &id); - - /* Set the USB device address to the value in the 'funcaddr' input */ - - ctrlreq->type = USB_REQ_DIR_OUT|USB_REQ_RECIPIENT_DEVICE; - ctrlreq->req = USB_REQ_SETADDRESS; - usbhost_putle16(ctrlreq->value, (uint16_t)funcaddr); - usbhost_putle16(ctrlreq->index, 0); - usbhost_putle16(ctrlreq->len, 0); - - ret = DRVR_CTRLOUT(drvr, ctrlreq, NULL); - if (ret != OK) - { - udbg("ERROR: SETADDRESS DRVR_CTRLOUT returned %d\n", ret); - goto errout; - } - usleep(2*1000); - - /* Modify control pipe with the provided USB device address */ - - DRVR_EP0CONFIGURE(drvr, funcaddr, maxpacketsize); - - /* Get the configuration descriptor (only), index == 0. Should not be - * hard-coded! More logic is needed in order to handle devices with - * multiple configurations. - */ - - ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE; - ctrlreq->req = USB_REQ_GETDESCRIPTOR; - usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8)); - usbhost_putle16(ctrlreq->index, 0); - usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC); - - ret = DRVR_CTRLIN(drvr, ctrlreq, buffer); - if (ret != OK) - { - udbg("ERROR: GETDESCRIPTOR/CONFIG, DRVR_CTRLIN returned %d\n", ret); - goto errout; - } - - /* Extract the full size of the configuration data */ - - cfglen = (unsigned int)usbhost_getle16(((struct usb_cfgdesc_s *)buffer)->totallen); - uvdbg("sizeof config data: %d\n", cfglen); - - /* Get all of the configuration descriptor data, index == 0 (Should not be - * hard-coded!) - */ - - ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE; - ctrlreq->req = USB_REQ_GETDESCRIPTOR; - usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8)); - usbhost_putle16(ctrlreq->index, 0); - usbhost_putle16(ctrlreq->len, cfglen); - - ret = DRVR_CTRLIN(drvr, ctrlreq, buffer); - if (ret != OK) - { - udbg("ERROR: GETDESCRIPTOR/CONFIG, DRVR_CTRLIN returned %d\n", ret); - goto errout; - } - - /* Select device configuration 1 (Should not be hard-coded!) */ - - ctrlreq->type = USB_REQ_DIR_OUT|USB_REQ_RECIPIENT_DEVICE; - ctrlreq->req = USB_REQ_SETCONFIGURATION; - usbhost_putle16(ctrlreq->value, 1); - usbhost_putle16(ctrlreq->index, 0); - usbhost_putle16(ctrlreq->len, 0); - - ret = DRVR_CTRLOUT(drvr, ctrlreq, NULL); - if (ret != OK) - { - udbg("ERROR: SETCONFIGURATION, DRVR_CTRLOUT returned %d\n", ret); - goto errout; - } - - /* Free the descriptor buffer that we were using for the request buffer. - * It is not needed further here but it may be needed by the class driver - * during its connection operations. - */ - - DRVR_FREE(drvr, (uint8_t*)ctrlreq); - ctrlreq = NULL; - - /* Was the class identification information provided in the device descriptor? - * Or do we need to find it in the interface descriptor(s)? - */ - - if (id.base == USB_CLASS_PER_INTERFACE) - { - /* Get the class identification information for this device from the - * interface descriptor(s). Hmmm.. More logic is need to handle the - * case of multiple interface descriptors. - */ - - ret = usbhost_configdesc(buffer, cfglen, &id); - if (ret != OK) - { - udbg("ERROR: usbhost_configdesc returned %d\n", ret); - goto errout; - } - } - - /* Some devices may require some delay before initialization */ - - usleep(100*1000); - - /* Parse the configuration descriptor and bind to the class instance for the - * device. This needs to be the last thing done because the class driver - * will begin configuring the device. - */ - - ret = usbhost_classbind(drvr, buffer, cfglen, &id, funcaddr, class); - if (ret != OK) - { - udbg("ERROR: usbhost_classbind returned %d\n", ret); - } - -errout: - if (buffer) - { - DRVR_FREE(drvr, buffer); - } - - if (ctrlreq) - { - DRVR_FREE(drvr, (uint8_t*)ctrlreq); - } - return ret; -} diff --git a/nuttx/drivers/usbhost/usbhost_findclass.c b/nuttx/drivers/usbhost/usbhost_findclass.c deleted file mode 100644 index 3e38670cf..000000000 --- a/nuttx/drivers/usbhost/usbhost_findclass.c +++ /dev/null @@ -1,199 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/usbhost_findclass.c - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include -#include - -#include "usbhost_registry.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_idmatch - * - * Description: - * Check if the class ID matches what the host controller found. - * - * Input Parameters: - * classid - ID info for the class under consideration. - * devid - ID info reported by the device. - * - * Returned Values: - * TRUE - the class will support this device. - * - ****************************************************************************/ - -static bool usbhost_idmatch(const struct usbhost_id_s *classid, - const struct usbhost_id_s *devid) -{ - uvdbg("Compare to class:%d subclass:%d protocol:%d vid:%04x pid:%04x\n", - classid->base, classid->subclass, classid->proto, - classid->vid, classid->pid); - - /* The base class ID, subclass and protocol have to match up in any event */ - - if (devid->base == classid->base && - devid->subclass == classid->subclass && - devid->proto == classid->proto) - { - /* If this is a vendor-specific class ID, then the VID and PID have to - * match as well. - */ - - if (devid->base == USB_CLASS_VENDOR_SPEC) - { - /* Vendor specific... do the VID and PID also match? */ - - if (devid->vid == classid->vid && devid->pid == classid->pid) - { - /* Yes.. then we have a match */ - - return true; - } - } - else - { - /* Not vendor specific? Then we have a match */ - - return true; - } - } - - /* No match.. not supported */ - - return false; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_findclass - * - * Description: - * Find a USB host class implementation previously registered by - * usbhost_registerclass(). On success, an instance of struct - * usbhost_registry_s will be returned. That instance will contain all of - * the information that will be needed to obtain and bind a struct - * usbhost_class_s instance for the device. - * - * Input Parameters: - * id - Identifies the USB device class that has connect to the USB host. - * - * Returned Values: - * On success this function will return a non-NULL instance of struct - * usbhost_registry_s. NULL will be returned on failure. This function - * can only fail if (1) id is NULL, or (2) no USB host class is registered - * that matches the device class ID. - * - ****************************************************************************/ - -const struct usbhost_registry_s *usbhost_findclass(const struct usbhost_id_s *id) -{ - struct usbhost_registry_s *class; - irqstate_t flags; - int ndx; - - DEBUGASSERT(id); - uvdbg("Looking for class:%d subclass:%d protocol:%d vid:%04x pid:%04x\n", - id->base, id->subclass, id->proto, id->vid, id->pid); - - /* g_classregistry is a singly-linkedlist of class ID information added by - * calls to usbhost_registerclass(). Since this list is accessed from USB - * host controller interrupt handling logic, accesses to this list must be - * protected by disabling interrupts. - */ - - flags = irqsave(); - - /* Examine each register class in the linked list */ - - for (class = g_classregistry; class; class = class->flink) - { - /* If the registered class supports more than one ID, subclass, or - * protocol, then try each. - */ - - uvdbg("Checking class:%p nids:%d\n", class, class->nids); - for (ndx = 0; ndx < class->nids; ndx++) - { - /* Did we find a matching ID? */ - - if (usbhost_idmatch(&class->id[ndx], id)) - { - /* Yes.. restore interrupts and return the class info */ - - irqrestore(flags); - return class; - } - } - } - - /* Not found... restore interrupts and return NULL */ - - irqrestore(flags); - return NULL; -} - diff --git a/nuttx/drivers/usbhost/usbhost_hidkbd.c b/nuttx/drivers/usbhost/usbhost_hidkbd.c deleted file mode 100644 index d6a9ceda3..000000000 --- a/nuttx/drivers/usbhost/usbhost_hidkbd.c +++ /dev/null @@ -1,2353 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/usbhost_hidkbd.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef CONFIG_HIDKBD_ENCODED -# include -# include -#endif - -/* Don't compile if prerequisites are not met */ - -#if defined(CONFIG_USBHOST) && !defined(CONFIG_USBHOST_INT_DISABLE) && CONFIG_NFILE_DESCRIPTORS > 0 - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* This determines how often the USB keyboard will be polled in units of - * of microseconds. The default is 100MS. - */ - -#ifndef CONFIG_HIDKBD_POLLUSEC -# define CONFIG_HIDKBD_POLLUSEC (100*1000) -#endif - -/* Worker thread is needed, unfortunately, to handle some cornercase failure - * conditions. This is kind of wasteful and begs for a re-design. - */ - -#ifndef CONFIG_SCHED_WORKQUEUE -# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" -#endif - -/* Signals must not be disabled as they are needed by usleep. Need to have - * CONFIG_DISABLE_SIGNALS=n - */ - -#ifdef CONFIG_DISABLE_SIGNALS -# warning "Signal support is required (CONFIG_DISABLE_SIGNALS)" -#endif - -/* Provide some default values for other configuration settings */ - -#ifndef CONFIG_HIDKBD_DEFPRIO -# define CONFIG_HIDKBD_DEFPRIO 50 -#endif - -#ifndef CONFIG_HIDKBD_STACKSIZE -# define CONFIG_HIDKBD_STACKSIZE 1024 -#endif - -#ifndef CONFIG_HIDKBD_BUFSIZE -# define CONFIG_HIDKBD_BUFSIZE 64 -#endif - -#ifndef CONFIG_HIDKBD_NPOLLWAITERS -# define CONFIG_HIDKBD_NPOLLWAITERS 2 -#endif - -/* The default is to support scancode mapping for the standard 104 key - * keyboard. Setting CONFIG_HIDKBD_RAWSCANCODES will disable all scancode - * mapping; Setting CONFIG_HIDKBD_ALLSCANCODES will enable mapping of all - * scancodes; - */ - -#ifndef CONFIG_HIDKBD_RAWSCANCODES -# ifdef CONFIG_HIDKBD_ALLSCANCODES -# define USBHID_NUMSCANCODES (USBHID_KBDUSE_MAX+1) -# else -# define USBHID_NUMSCANCODES 104 -# endif -#endif - -/* We cant support encoding of special characters of unless the Keyboard - * CODEC is enabled. - */ - -#ifndef CONFIG_LIB_KBDCODEC -# undef CONFIG_HIDKBD_ENCODED -#endif - -/* If we are using raw scancodes, then we cannot support encoding of - * special characters either. - */ - -#ifdef CONFIG_HIDKBD_RAWSCANCODES -# undef CONFIG_HIDKBD_ENCODED -#endif - -/* Driver support ***********************************************************/ -/* This format is used to construct the /dev/kbd[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/kbd%c" -#define DEV_NAMELEN 11 - -/* Used in usbhost_cfgdesc() */ - -#define USBHOST_IFFOUND 0x01 /* Required I/F descriptor found */ -#define USBHOST_EPINFOUND 0x02 /* Required interrupt IN EP descriptor found */ -#define USBHOST_EPOUTFOUND 0x04 /* Optional interrupt OUT EP descriptor found */ -#define USBHOST_RQDFOUND (USBHOST_IFFOUND|USBHOST_EPINFOUND) -#define USBHOST_ALLFOUND (USBHOST_RQDFOUND|USBHOST_EPOUTFOUND) - -#define USBHOST_MAX_CREFS 0x7fff - -/* Debug ********************************************************************/ -/* Both CONFIG_DEBUG_INPUT and CONFIG_DEBUG_USB could apply to this file. - * We assume here that CONFIG_DEBUG_INPUT might be enabled separately, but - * CONFIG_DEBUG_USB implies both. - */ - -#ifndef CONFIG_DEBUG_INPUT -# undef idbg -# define idbg udbg -# undef illdbg -# define illdbg ulldbg -# undef ivdbg -# define ivdbg uvdbg -# undef illvdbg -# define illvdbg ullvdbg -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure contains the internal, private state of the USB host - * keyboard storage class. - */ - -struct usbhost_state_s -{ - /* This is the externally visible portion of the state */ - - struct usbhost_class_s class; - - /* This is an instance of the USB host driver bound to this class instance */ - - struct usbhost_driver_s *drvr; - - /* The remainder of the fields are provide o the keyboard class driver */ - - char devchar; /* Character identifying the /dev/kbd[n] device */ - volatile bool disconnected; /* TRUE: Device has been disconnected */ - volatile bool polling; /* TRUE: Poll thread is running */ - volatile bool open; /* TRUE: The keyboard device is open */ - volatile bool waiting; /* TRUE: waiting for keyboard data */ - uint8_t ifno; /* Interface number */ - int16_t crefs; /* Reference count on the driver instance */ - sem_t exclsem; /* Used to maintain mutual exclusive access */ - sem_t waitsem; /* Used to wait for keyboard data */ - FAR uint8_t *tbuffer; /* The allocated transfer buffer */ - size_t tbuflen; /* Size of the allocated transfer buffer */ - pid_t pollpid; /* PID of the poll task */ - struct work_s work; /* For cornercase error handling by the worker thread */ - - /* Endpoints: - * EP0 (Control): - * - Receiving and responding to requests for USB control and class data. - * - IN data when polled by the HID class driver (Get_Report) - * - OUT data from the host. - * EP Interrupt IN: - * - Receiving asynchronous (unrequested) IN data from the device. - * EP Interrrupt OUT (optional): - * - Transmitting low latency OUT data to the device. - * - If not present, EP0 used. - */ - - usbhost_ep_t epin; /* Interrupt IN endpoint */ - usbhost_ep_t epout; /* Optional interrupt OUT endpoint */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_HIDKBD_NPOLLWAITERS]; -#endif - - /* Buffer used to collect and buffer incoming keyboard characters */ - - volatile uint16_t headndx; /* Buffer head index */ - volatile uint16_t tailndx; /* Buffer tail index */ - uint8_t kbdbuffer[CONFIG_HIDKBD_BUFSIZE]; -}; - -/* This type is used for encoding special characters */ - -#ifdef CONFIG_HIDKBD_ENCODED -struct usbhost_outstream_s -{ - struct lib_outstream_s stream; - FAR struct usbhost_state_s *priv; -}; -#endif - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Semaphores */ - -static void usbhost_takesem(sem_t *sem); -#define usbhost_givesem(s) sem_post(s); - -/* Polling support */ - -#ifndef CONFIG_DISABLE_POLL -static void usbhost_pollnotify(FAR struct usbhost_state_s *dev); -#else -# define usbhost_pollnotify(dev) -#endif - -/* Memory allocation services */ - -static inline FAR struct usbhost_state_s *usbhost_allocclass(void); -static inline void usbhost_freeclass(FAR struct usbhost_state_s *class); - -/* Device name management */ - -static int usbhost_allocdevno(FAR struct usbhost_state_s *priv); -static void usbhost_freedevno(FAR struct usbhost_state_s *priv); -static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname); - -/* Keyboard polling thread */ - -static void usbhost_destroy(FAR void *arg); -static void usbhost_putbuffer(FAR struct usbhost_state_s *priv, uint8_t keycode); -#ifdef CONFIG_HIDKBD_ENCODED -static void usbhost_putstream(FAR struct lib_outstream_s *this, int ch); -#endif -static inline uint8_t usbhost_mapscancode(uint8_t scancode, uint8_t modifier); -#ifdef CONFIG_HIDKBD_ENCODED -static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv, - uint8_t scancode, uint8_t modifier); -#endif -static int usbhost_kbdpoll(int argc, char *argv[]); - -/* Helpers for usbhost_connect() */ - -static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr); -static inline int usbhost_devinit(FAR struct usbhost_state_s *priv); - -/* (Little Endian) Data helpers */ - -static inline uint16_t usbhost_getle16(const uint8_t *val); -static inline void usbhost_putle16(uint8_t *dest, uint16_t val); -static inline uint32_t usbhost_getle32(const uint8_t *val); -#if 0 /* Not used */ -static void usbhost_putle32(uint8_t *dest, uint32_t val); -#endif - -/* Transfer descriptor memory management */ - -static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv); -static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv); - -/* struct usbhost_registry_s methods */ - -static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id); - -/* struct usbhost_class_s methods */ - -static int usbhost_connect(FAR struct usbhost_class_s *class, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr); -static int usbhost_disconnected(FAR struct usbhost_class_s *class); - -/* Driver methods. We export the keyboard as a standard character driver */ - -static int usbhost_open(FAR struct file *filep); -static int usbhost_close(FAR struct file *filep); -static ssize_t usbhost_read(FAR struct file *filep, - FAR char *buffer, size_t len); -static ssize_t usbhost_write(FAR struct file *filep, - FAR const char *buffer, size_t len); -#ifndef CONFIG_DISABLE_POLL -static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This structure provides the registry entry ID informatino that will be - * used to associate the USB host keyboard class driver to a connected USB - * device. - */ - -static const const struct usbhost_id_s g_id = -{ - USB_CLASS_HID, /* base */ - USBHID_SUBCLASS_BOOTIF, /* subclass */ - USBHID_PROTOCOL_KEYBOARD, /* proto */ - 0, /* vid */ - 0 /* pid */ -}; - -/* This is the USB host storage class's registry entry */ - -static struct usbhost_registry_s g_skeleton = -{ - NULL, /* flink */ - usbhost_create, /* create */ - 1, /* nids */ - &g_id /* id[] */ -}; - -static const struct file_operations usbhost_fops = -{ - usbhost_open, /* open */ - usbhost_close, /* close */ - usbhost_read, /* read */ - usbhost_write, /* write */ - 0, /* seek */ - 0 /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , usbhost_poll /* poll */ -#endif -}; - -/* This is a bitmap that is used to allocate device names /dev/kbda-z. */ - -static uint32_t g_devinuse; - -/* The following are used to managed the class creation operation */ - -static sem_t g_exclsem; /* For mutually exclusive thread creation */ -static sem_t g_syncsem; /* Thread data passing interlock */ -static struct usbhost_state_s *g_priv; /* Data passed to thread */ - -/* The following tables map keyboard scan codes to printable ASIC - * characters. There is no support here for function keys or cursor - * controls. - */ - -#ifndef CONFIG_HIDKBD_RAWSCANCODES -#ifdef CONFIG_HIDKBD_ENCODED - -/* The first and last scancode values with encode-able values */ - -#define FIRST_ENCODING USBHID_KBDUSE_ENTER /* 0x28 Keyboard Return (ENTER) */ -#ifndef CONFIG_HIDKBD_ALLSCANCODES -# define LAST_ENCODING USBHID_KBDUSE_POWER /* 0x66 Keyboard Power */ -#else -# define LAST_ENCODING USBHID_KBDUSE_KPDHEXADECIMAL /* 0xdd Keypad Hexadecimal */ -#endif - -#define USBHID_NUMENCODINGS (LAST_ENCODING - FIRST_ENCODING + 1) - -static const uint8_t encoding[USBHID_NUMENCODINGS] = -{ - /* 0x28-0x2f: Enter,escape,del,back-tab,space,_,+,{ */ - - KEYCODE_ENTER, 0, KEYCODE_FWDDEL, KEYCODE_BACKDEL, 0, 0, 0, 0, - - /* 0x30-0x37: },|,Non-US tilde,:,",grave tilde,<,> */ - - 0, 0, 0, 0, 0, 0, 0, 0, - - /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */ - - 0, KEYCODE_CAPSLOCK, KEYCODE_F1, KEYCODE_F2, KEYCODE_F3, KEYCODE_F4, KEYCODE_F5, KEYCODE_F6, - - /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */ - - KEYCODE_F7, KEYCODE_F8, KEYCODE_F9, KEYCODE_F10, KEYCODE_F11, KEYCODE_F12, KEYCODE_PRTSCRN, KEYCODE_SCROLLLOCK, - - /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */ - - KEYCODE_PAUSE, KEYCODE_INSERT, KEYCODE_HOME, KEYCODE_PAGEUP, KEYCODE_FWDDEL, KEYCODE_END, KEYCODE_PAGEDOWN, KEYCODE_RIGHT, - - /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */ - - KEYCODE_LEFT, KEYCODE_DOWN, KEYCODE_UP, KEYCODE_NUMLOCK, 0, 0, 0, 0, - - /* 0x58-0x5f: Enter,1-7 */ - - KEYCODE_ENTER, 0, 0, 0, 0, 0, 0, 0, - - /* 0x60-0x66: 8-9,0,.,Non-US \,Application,Power */ - - 0, 0, 0, 0, 0, 0, KEYCODE_POWER, - -#ifdef CONFIG_HIDKBD_ALLSCANCODES - - 0, /* 0x67 = */ - - /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */ - - KEYCODE_F13, KEYCODE_F14, KEYCODE_F15, KEYCODE_F16, KEYCODE_F17, KEYCODE_F18, KEYCODE_F19, KEYCODE_F20, - - /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */ - - KEYCODE_F21, KEYCODE_F22, KEYCODE_F23, KEYCODE_F24, KEYCODE_EXECUTE, KEYCODE_HELP, KEYCODE_MENU, KEYCODE_SELECT, - - /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */ - - KEYCODE_STOP, KEYCODE_AGAIN, KEYCODE_UNDO, KEYCODE_CUT, KEYCODE_COPY, KEYCODE_PASTE, KEYCODE_FIND, KEYCODE_MUTE, - - /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */ - - KEYCODE_VOLUP, KEYCODE_VOLDOWN, KEYCODE_LCAPSLOCK, KEYCODE_LNUMLOCK, KEYCODE_LSCROLLLOCK, 0, 0, 0, - - /* 0x88-0x8f: International 2-9 */ - - 0, 0, 0, 0, 0, 0, 0, 0, - - /* 0x90-0x97: LAN 1-8 */ - - KEYCODE_LANG1, KEYCODE_LANG2, KEYCODE_LANG3, KEYCODE_LANG4, KEYCODE_LANG5, KEYCODE_LANG6, KEYCODE_LANG7, KEYCODE_LANG8, - - /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */ - - 0, 0, KEYCODE_SYSREQ, KEYCODE_CANCEL, KEYCODE_CLEAR, 0, KEYCODE_ENTER, 0, - - /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */ - - 0, 0, 0, 0, 0, 0, 0, 0, - - /* 0xa8-0xaf: (reserved) */ - - 0, 0, 0, 0, 0, 0, 0, 0, - - /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */ - - 0, 0, 0, 0, 0, 0, 0, 0, - - /* 0xb8-0xbf: {,},tab,backspace,A-D */ - - 0, 0, 0, KEYCODE_BACKDEL, 0, 0, 0, 0, - - /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */ - - 0, 0, 0, 0, 0, 0, 0, 0, - - /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */ - - 0, 0, 0, 0, 0, 0, 0, 0, - - /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */ - - KEYCODE_MEMSTORE, KEYCODE_MEMRECALL, KEYCODE_MEMCLEAR, KEYCODE_MEMADD, KEYCODE_MEMSUB, KEYCODE_MEMMUL, KEYCODE_MEMDIV, KEYCODE_NEGATE, - - /* 0xd8-0xdd: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */ - - KEYCODE_CLEAR, KEYCODE_CLEARENTRY, KEYCODE_BINARY, KEYCODE_OCTAL, KEYCODE_DECIMAL, KEYCODE_HEXADECIMAL -#endif -}; - -#endif - -static const uint8_t ucmap[USBHID_NUMSCANCODES] = -{ - 0, 0, 0, 0, 'A', 'B', 'C', 'D', /* 0x00-0x07: Reserved, errors, A-D */ - 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', /* 0x08-0x0f: E-L */ - 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 0x10-0x17: M-T */ - 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', /* 0x18-0x1f: U-Z,!,@ */ - '#', '$', '%', '^', '&', '*', '(', ')', /* 0x20-0x27: #,$,%,^,&,*,(,) */ - '\n', '\033', '\177', 0, ' ', '_', '+', '{', /* 0x28-0x2f: Enter,escape,del,back-tab,space,_,+,{ */ - '}', '|', 0, ':', '"', '~', '<', '>', /* 0x30-0x37: },|,Non-US tilde,:,",grave tilde,<,> */ - '?', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */ - 0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */ - '\n', '1', '2', '3', '4', '5', '6', '7', /* 0x58-0x5f: Enter,1-7 */ - '8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */ -#ifdef CONFIG_HIDKBD_ALLSCANCODES - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */ - 0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */ - 0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */ - 0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */ - '{', '}', '\t', \177, 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */ - 'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */ - 0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */ -#endif -}; - -static const uint8_t lcmap[USBHID_NUMSCANCODES] = -{ - 0, 0, 0, 0, 'a', 'b', 'c', 'd', /* 0x00-0x07: Reserved, errors, a-d */ - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', /* 0x08-0x0f: e-l */ - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 0x10-0x17: m-t */ - 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', /* 0x18-0x1f: u-z,1-2 */ - '3', '4', '5', '6', '7', '8', '9', '0', /* 0x20-0x27: 3-9,0 */ - '\n', '\033', '\177', '\t', ' ', '-', '=', '[', /* 0x28-0x2f: Enter,escape,del,tab,space,-,=,[ */ - ']', '\\', '\234', ';', '\'', '`', ',', '.', /* 0x30-0x37: ],\,Non-US pound,;,',grave accent,,,. */ - '/', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */ - 0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */ - '\n', '1', '2', '3', '4', '5', '6', '7', /* 0x58-0x5f: Enter,1-7 */ - '8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */ -#ifdef CONFIG_HIDKBD_ALLSCANCODES - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */ - 0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */ - 0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */ - 0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */ - '{', '}', '\t', '\177', 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */ - 'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */ - 0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */ -#endif -}; -#endif /* CONFIG_HIDKBD_RAWSCANCODES */ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_takesem - * - * Description: - * This is just a wrapper to handle the annoying behavior of semaphore - * waits that return due to the receipt of a signal. - * - ****************************************************************************/ - -static void usbhost_takesem(sem_t *sem) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(sem) != 0) - { - /* The only case that an error should occr here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -/**************************************************************************** - * Name: usbhost_pollnotify - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static void usbhost_pollnotify(FAR struct usbhost_state_s *priv) -{ - int i; - - for (i = 0; i < CONFIG_HIDKBD_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= (fds->events & POLLIN); - if (fds->revents != 0) - { - uvdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } - } -} -#endif - -/**************************************************************************** - * Name: usbhost_allocclass - * - * Description: - * This is really part of the logic that implements the create() method - * of struct usbhost_registry_s. This function allocates memory for one - * new class instance. - * - * Input Parameters: - * None - * - * Returned Values: - * On success, this function will return a non-NULL instance of struct - * usbhost_class_s. NULL is returned on failure; this function will - * will fail only if there are insufficient resources to create another - * USB host class instance. - * - ****************************************************************************/ - -static inline FAR struct usbhost_state_s *usbhost_allocclass(void) -{ - FAR struct usbhost_state_s *priv; - - DEBUGASSERT(!up_interrupt_context()); - priv = (FAR struct usbhost_state_s *)kmalloc(sizeof(struct usbhost_state_s)); - uvdbg("Allocated: %p\n", priv);; - return priv; -} - -/**************************************************************************** - * Name: usbhost_freeclass - * - * Description: - * Free a class instance previously allocated by usbhost_allocclass(). - * - * Input Parameters: - * class - A reference to the class instance to be freed. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline void usbhost_freeclass(FAR struct usbhost_state_s *class) -{ - DEBUGASSERT(class != NULL); - - /* Free the class instance. */ - - uvdbg("Freeing: %p\n", class);; - kfree(class); -} - -/**************************************************************************** - * Name: Device name management - * - * Description: - * Some tiny functions to coordinate management of device names. - * - ****************************************************************************/ - -static int usbhost_allocdevno(FAR struct usbhost_state_s *priv) -{ - irqstate_t flags; - int devno; - - flags = irqsave(); - for (devno = 0; devno < 26; devno++) - { - uint32_t bitno = 1 << devno; - if ((g_devinuse & bitno) == 0) - { - g_devinuse |= bitno; - priv->devchar = 'a' + devno; - irqrestore(flags); - return OK; - } - } - - irqrestore(flags); - return -EMFILE; -} - -static void usbhost_freedevno(FAR struct usbhost_state_s *priv) -{ - int devno = 'a' - priv->devchar; - - if (devno >= 0 && devno < 26) - { - irqstate_t flags = irqsave(); - g_devinuse &= ~(1 << devno); - irqrestore(flags); - } -} - -static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname) -{ - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar); -} - -/**************************************************************************** - * Name: usbhost_destroy - * - * Description: - * The USB device has been disconnected and the refernce count on the USB - * host class instance has gone to 1.. Time to destroy the USB host class - * instance. - * - * Input Parameters: - * arg - A reference to the class instance to be destroyed. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_destroy(FAR void *arg) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg; - char devname[DEV_NAMELEN]; - - DEBUGASSERT(priv != NULL); - uvdbg("crefs: %d\n", priv->crefs); - - /* Unregister the driver */ - - uvdbg("Unregister driver\n"); - usbhost_mkdevname(priv, devname); - (void)unregister_driver(devname); - - /* Release the device name used by this connection */ - - usbhost_freedevno(priv); - - /* Free the interrupt endpoints */ - - if (priv->epin) - { - DRVR_EPFREE(priv->drvr, priv->epin); - } - - if (priv->epout) - { - DRVR_EPFREE(priv->drvr, priv->epout); - } - - /* Free any transfer buffers */ - - usbhost_tdfree(priv); - - /* Destroy the semaphores */ - - sem_destroy(&priv->exclsem); - sem_destroy(&priv->waitsem); - - /* Disconnect the USB host device */ - - DRVR_DISCONNECT(priv->drvr); - - /* And free the class instance. Hmmm.. this may execute on the worker - * thread and the work structure is part of what is getting freed. That - * should be okay because once the work contained is removed from the - * queue, it should not longer be accessed by the worker thread. - */ - - usbhost_freeclass(priv); -} - -/**************************************************************************** - * Name: usbhost_putbuffer - * - * Description: - * Add one character to the user buffer. - * - * Input Parameters: - * priv - Driver internal state - * keycode - The value to add to the user buffer - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putbuffer(FAR struct usbhost_state_s *priv, - uint8_t keycode) -{ - register unsigned int head; - register unsigned int tail; - - /* Copy the next keyboard character into the user buffer. */ - - head = priv->headndx; - priv->kbdbuffer[head] = keycode; - - /* Increment the head index */ - - if (++head >= CONFIG_HIDKBD_BUFSIZE) - { - head = 0; - } - - /* If the buffer is full, then increment the tail index to make space. Is - * it better to lose old keystrokes or new? - */ - - tail = priv->tailndx; - if (tail == head) - { - if (++tail >= CONFIG_HIDKBD_BUFSIZE) - { - tail = 0; - } - - /* Save the updated tail index */ - - priv->tailndx = tail; - } - - /* Save the updated head index */ - - priv->headndx = head; -} - -/**************************************************************************** - * Name: usbhost_putstream - * - * Description: - * A wrapper for usbhost_putc that is compatibile with the lib_outstream_s - * putc methos. - * - * Input Parameters: - * stream - The struct lib_outstream_s reference - * ch - The character to add to the user buffer - * - * Returned Values: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_HIDKBD_ENCODED -static void usbhost_putstream(FAR struct lib_outstream_s *stream, int ch) -{ - FAR struct usbhost_outstream_s *privstream = (FAR struct usbhost_outstream_s *)stream; - - DEBUGASSERT(privstream && privstream->priv); - usbhost_putbuffer(privstream->priv, (uint8_t)ch); - stream->nput++; -} -#endif - -/**************************************************************************** - * Name: usbhost_mapscancode - * - * Description: - * Map a keyboard scancode to a printable ASCII character. There is no - * support here for function keys or cursor controls in this version of - * the driver. - * - * Input Parameters: - * scancode - Scan code to be mapped. - * modifier - Ctrl,Alt,Shift,GUI modifier bits - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline uint8_t usbhost_mapscancode(uint8_t scancode, uint8_t modifier) -{ -#ifndef CONFIG_HIDKBD_RAWSCANCODES - /* Range check */ - - if (scancode >= USBHID_NUMSCANCODES) - { - return 0; - } - - /* Is either shift key pressed? */ - - if ((modifier & (USBHID_MODIFER_LSHIFT|USBHID_MODIFER_RSHIFT)) != 0) - { - return ucmap[scancode]; - } - else - { - return lcmap[scancode]; - } -#else - return scancode; -#endif -} - -/**************************************************************************** - * Name: usbhost_encodescancode - * - * Description: - * Check if the key has a special function encoding and, if it does, add - * the encoded value to the user buffer. - * - * Input Parameters: - * priv - Driver internal state - * scancode - Scan code to be mapped. - * modifier - Ctrl,Alt,Shift,GUI modifier bits - * - * Returned Values: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_HIDKBD_ENCODED -static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv, - uint8_t scancode, uint8_t modifier) -{ - uint8_t encoded; - - /* Check if the raw scancode is in a valid range */ - - if (scancode >= FIRST_ENCODING && scancode <= LAST_ENCODING) - { - /* Yes the value is within range */ - - encoded = encoding[scancode - FIRST_ENCODING]; - ivdbg(" scancode: %02x modifier: %02x encoded: %d\n", - scancode, modifier, encoded); - - if (encoded) - { - struct usbhost_outstream_s usbstream; - - /* And it does correspond to a special function key */ - - usbstream.stream.put = usbhost_putstream; - usbstream.stream.nput = 0; - usbstream.priv = priv; - - /* Add the special function value to the user buffer */ - - kbd_specpress((enum kbd_keycode_e)encoded, - (FAR struct lib_outstream_s *)&usbstream); - } - } -} -#endif - -/**************************************************************************** - * Name: usbhost_kbdpoll - * - * Description: - * Periodically check for new keyboard data. - * - * Input Parameters: - * arg - A reference to the class instance to be destroyed. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static int usbhost_kbdpoll(int argc, char *argv[]) -{ - FAR struct usbhost_state_s *priv; - FAR struct usb_ctrlreq_s *ctrlreq; -#ifndef CONFIG_HIDKBD_NODEBOUNCE - uint8_t lastkey[6] = {0, 0, 0, 0, 0, 0}; -#endif -#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE) - unsigned int npolls = 0; -#endif - unsigned int nerrors = 0; - bool empty = true; - bool newstate; - int ret; - - uvdbg("Started\n"); - - /* Synchronize with the start-up logic. Get the private instance, re-start - * the start-up logic, and wait a bit to make sure that all of the class - * creation logic has a chance to run to completion. - * - * NOTE: that the reference count is incremented here. Therefore, we know - * that the driver data structure will remain stable while this thread is - * running. - */ - - priv = g_priv; - DEBUGASSERT(priv != NULL); - - priv->polling = true; - priv->crefs++; - usbhost_givesem(&g_syncsem); - sleep(1); - - /* Loop here until the device is disconnected */ - - uvdbg("Entering poll loop\n"); - - while (!priv->disconnected) - { - /* Make sure that we have exclusive access to the private data - * structure. There may now be other tasks with the character driver - * open and actively trying to interact with the class driver. - */ - - usbhost_takesem(&priv->exclsem); - - /* Format the HID report request: - * - * bmRequestType 10100001 - * bRequest GET_REPORT (0x01) - * wValue Report Type and Report Index - * wIndex Interface Number - * wLength Descriptor Length - * Data Descriptor Data - */ - - ctrlreq = (struct usb_ctrlreq_s *)priv->tbuffer; - ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE; - ctrlreq->req = USBHID_REQUEST_GETREPORT; - - usbhost_putle16(ctrlreq->value, (USBHID_REPORTTYPE_INPUT << 8)); - usbhost_putle16(ctrlreq->index, priv->ifno); - usbhost_putle16(ctrlreq->len, sizeof(struct usbhid_kbdreport_s)); - - /* Send HID report request */ - - ret = DRVR_CTRLIN(priv->drvr, ctrlreq, priv->tbuffer); - usbhost_givesem(&priv->exclsem); - - /* Check for errors -- Bail if an excessive number of errors - * are encountered. - */ - - if (ret != OK) - { - nerrors++; - udbg("ERROR: GETREPORT/INPUT, DRVR_CTRLIN returned: %d/%d\n", - ret, nerrors); - - if (nerrors > 200) - { - udbg("Too many errors... aborting: %d\n", nerrors); - break; - } - } - - /* The report was received correctly. But ignore the keystrokes if no - * task has opened the driver. - */ - - else if (priv->open) - { - struct usbhid_kbdreport_s *rpt = (struct usbhid_kbdreport_s *)priv->tbuffer; - uint8_t keycode; - int i; - - /* Add the newly received keystrokes to our internal buffer */ - - usbhost_takesem(&priv->exclsem); - for (i = 0; i < 6; i++) - { - /* Is this key pressed? But not pressed last time? - * HID spec: "The order of keycodes in array fields has no - * significance. Order determination is done by the host - * software comparing the contents of the previous report to - * the current report. If two or more keys are reported in - * one report, their order is indeterminate. Keyboards may - * buffer events that would have otherwise resulted in - * multiple event in a single report. - * - * "'Repeat Rate' and 'Delay Before First Repeat' are - * implemented by the host and not in the keyboard (this - * means the BIOS in legacy mode). The host may use the - * device report rate and the number of reports to determine - * how long a key is being held down. Alternatively, the host - * may use its own clock or the idle request for the timing - * of these features." - */ - - if (rpt->key[i] != USBHID_KBDUSE_NONE -#ifndef CONFIG_HIDKBD_NODEBOUNCE - && rpt->key[i] != lastkey[i] -#endif - ) - { - /* Yes.. Add it to the buffer. */ - - /* Map the keyboard scancode to a printable ASCII - * character. There is no support here for function keys - * or cursor controls in this version of the driver. - */ - - keycode = usbhost_mapscancode(rpt->key[i], rpt->modifier); - ivdbg("Key %d: %02x keycode:%c modifier: %02x\n", - i, rpt->key[i], keycode ? keycode : ' ', rpt->modifier); - - /* Zero at this point means that the key does not map to a - * printable character. - */ - - if (keycode != 0) - { - /* Handle control characters. Zero after this means - * a valid, NUL character. - */ - - if ((rpt->modifier & (USBHID_MODIFER_LCTRL|USBHID_MODIFER_RCTRL)) != 0) - { - keycode &= 0x1f; - } - - /* Copy the next keyboard character into the user - * buffer. - */ - - usbhost_putbuffer(priv, keycode); - } - - /* The zero might, however, map to a special keyboard action (such as a - * cursor movement or function key). Attempt to encode the special key. - */ - -#ifdef CONFIG_HIDKBD_ENCODED - else - { - usbhost_encodescancode(priv, rpt->key[i], rpt->modifier); - } -#endif - } - - /* Save the scancode (or lack thereof) for key debouncing on - * next keyboard report. - */ - -#ifndef CONFIG_HIDKBD_NODEBOUNCE - lastkey[i] = rpt->key[i]; -#endif - } - - /* Is there data available? */ - - newstate = (priv->headndx == priv->tailndx); - if (!newstate) - { - /* Yes.. Is there a thread waiting for keyboard data now? */ - - if (priv->waiting) - { - /* Yes.. wake it up */ - - usbhost_givesem(&priv->waitsem); - priv->waiting = false; - } - - /* Did we just transition from no data available to data - * available? If so, wake up any threads waiting for the - * POLLIN event. - */ - - if (empty) - { - usbhost_pollnotify(priv); - } - } - - empty = newstate; - usbhost_givesem(&priv->exclsem); - } - - /* If USB debug is on, then provide some periodic indication that - * polling is still happening. - */ - -#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE) - npolls++; - if ((npolls & 31) == 0) - { - udbg("Still polling: %d\n", npolls); - } -#endif - /* Wait for the required amount (or until a signal is received). We - * will wake up when either the delay elapses or we are signalled that - * the device has been disconnected. - */ - - usleep(CONFIG_HIDKBD_POLLUSEC); - } - - /* We get here when the driver is removed.. or when too many errors have - * been encountered. - * - * Make sure that we have exclusive access to the private data structure. - * There may now be other tasks with the character driver open and actively - * trying to interact with the class driver. - */ - - usbhost_takesem(&priv->exclsem); - - /* Indicate that we are no longer running and decrement the reference - * count help by this thread. If there are no other users of the class, - * we can destroy it now. Otherwise, we have to wait until the all - * of the file descriptors are closed. - */ - - udbg("Keyboard removed, polling halted\n"); - priv->polling = false; - if (--priv->crefs < 2) - { - /* Destroy the instance (while we hold the semaphore!) */ - - usbhost_destroy(priv); - } - else - { - /* No, we will destroy the driver instance when it is finally closed */ - - usbhost_givesem(&priv->exclsem); - } - - return 0; -} - -/**************************************************************************** - * Name: usbhost_cfgdesc - * - * Description: - * This function implements the connect() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to provide the device's configuration - * descriptor to the class so that the class may initialize properly - * - * Input Parameters: - * priv - The USB host class instance. - * configdesc - A pointer to a uint8_t buffer container the configuration descripor. - * desclen - The length in bytes of the configuration descriptor. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * Assumptions: - * This function will *not* be called from an interrupt handler. - * - ****************************************************************************/ - -static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr) -{ - FAR struct usb_cfgdesc_s *cfgdesc; - FAR struct usb_desc_s *desc; - FAR struct usbhost_epdesc_s epindesc; - FAR struct usbhost_epdesc_s epoutdesc; - int remaining; - uint8_t found = 0; - bool done = false; - int ret; - - DEBUGASSERT(priv != NULL && - configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); - - /* Verify that we were passed a configuration descriptor */ - - cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc; - if (cfgdesc->type != USB_DESC_TYPE_CONFIG) - { - return -EINVAL; - } - - /* Get the total length of the configuration descriptor (little endian). - * It might be a good check to get the number of interfaces here too. - */ - - remaining = (int)usbhost_getle16(cfgdesc->totallen); - - /* Skip to the next entry descriptor */ - - configdesc += cfgdesc->len; - remaining -= cfgdesc->len; - - /* Loop where there are more dscriptors to examine */ - - while (remaining >= sizeof(struct usb_desc_s) && !done) - { - /* What is the next descriptor? */ - - desc = (FAR struct usb_desc_s *)configdesc; - switch (desc->type) - { - /* Interface descriptor. We really should get the number of endpoints - * from this descriptor too. - */ - - case USB_DESC_TYPE_INTERFACE: - { - FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc; - - uvdbg("Interface descriptor\n"); - DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC); - - /* Did we already find what we needed from a preceding interface? */ - - if ((found & USBHOST_RQDFOUND) == USBHOST_RQDFOUND) - { - /* Yes.. then break out of the loop and use the preceding - * interface. - */ - - done = true; - } - else - { - /* Otherwise, save the interface number and discard any - * endpoints previously found - */ - - priv->ifno = ifdesc->ifno; - found = USBHOST_IFFOUND; - } - } - break; - - /* HID descriptor */ - - case USBHID_DESCTYPE_HID: - uvdbg("HID descriptor\n"); - break; - - /* Endpoint descriptor. We expect one or two interrupt endpoints, - * a required IN endpoint and an optional OUT endpoint. - */ - - case USB_DESC_TYPE_ENDPOINT: - { - FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc; - - uvdbg("Endpoint descriptor\n"); - DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC); - - /* Check for an interrupt endpoint. */ - - if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_INT) - { - /* Yes.. it is a interrupt endpoint. IN or OUT? */ - - if (USB_ISEPOUT(epdesc->addr)) - { - /* It is an interrupt OUT endpoint. There not be more than one - * interrupt OUT endpoint. - */ - - if ((found & USBHOST_EPOUTFOUND) != 0) - { - /* Oops.. more than one endpoint. We don't know what to do with this. */ - - return -EINVAL; - } - found |= USBHOST_EPOUTFOUND; - - /* Save the interrupt OUT endpoint information */ - - epoutdesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; - epoutdesc.in = false; - epoutdesc.funcaddr = funcaddr; - epoutdesc.xfrtype = USB_EP_ATTR_XFER_INT; - epoutdesc.interval = epdesc->interval; - epoutdesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); - uvdbg("Interrupt OUT EP addr:%d mxpacketsize:%d\n", - epoutdesc.addr, epoutdesc.mxpacketsize); - } - else - { - /* It is an interrupt IN endpoint. There should be only - * one interrupt IN endpoint. - */ - - if ((found & USBHOST_EPINFOUND) != 0) - { - /* Oops.. more than one endpint. We don't know what - * to do with this. - */ - - return -EINVAL; - } - found |= USBHOST_EPINFOUND; - - /* Save the interrupt IN endpoint information */ - - epindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; - epindesc.in = 1; - epindesc.funcaddr = funcaddr; - epindesc.xfrtype = USB_EP_ATTR_XFER_INT; - epindesc.interval = epdesc->interval; - epindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); - uvdbg("Interrupt IN EP addr:%d mxpacketsize:%d\n", - epindesc.addr, epindesc.mxpacketsize); - } - } - } - break; - - /* Other descriptors are just ignored for now */ - - default: - uvdbg("Other descriptor: %d\n", desc->type); - break; - } - - /* What we found everything that we are going to find? */ - - if (found == USBHOST_ALLFOUND) - { - /* Yes.. then break out of the loop and use the preceding interface */ - - done = true; - } - - /* Increment the address of the next descriptor */ - - configdesc += desc->len; - remaining -= desc->len; - } - - /* Sanity checking... did we find all of things that we need? */ - - if ((found & USBHOST_RQDFOUND) != USBHOST_RQDFOUND) - { - ulldbg("ERROR: Found IF:%s EPIN:%s\n", - (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO", - (found & USBHOST_EPINFOUND) != 0 ? "YES" : "NO"); - return -EINVAL; - } - - /* We are good... Allocate the endpoints. First, the required interrupt - * IN endpoint. - */ - - ret = DRVR_EPALLOC(priv->drvr, &epindesc, &priv->epin); - if (ret != OK) - { - udbg("ERROR: Failed to allocate interrupt IN endpoint\n"); - return ret; - } - - /* Then the optional interrupt OUT endpoint */ - - ullvdbg("Found EPOOUT:%s\n", - (found & USBHOST_EPOUTFOUND) != 0 ? "YES" : "NO"); - - if ((found & USBHOST_EPOUTFOUND) != 0) - { - ret = DRVR_EPALLOC(priv->drvr, &epoutdesc, &priv->epout); - if (ret != OK) - { - udbg("ERROR: Failed to allocate interrupt OUT endpoint\n"); - (void)DRVR_EPFREE(priv->drvr, priv->epin); - return ret; - } - } - - ullvdbg("Endpoints allocated\n"); - return OK; -} - -/**************************************************************************** - * Name: usbhost_devinit - * - * Description: - * The USB device has been successfully connected. This completes the - * initialization operations. It is first called after the - * configuration descriptor has been received. - * - * This function is called from the connect() method. This function always - * executes on the thread of the caller of connect(). - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline int usbhost_devinit(FAR struct usbhost_state_s *priv) -{ - char devname[DEV_NAMELEN]; - int ret; - - /* Set aside a transfer buffer for exclusive use by the keyboard class driver */ - - ret = usbhost_tdalloc(priv); - if (ret != OK) - { - udbg("ERROR: Failed to allocate transfer buffer\n"); - return ret; - } - - /* Increment the reference count. This will prevent usbhost_destroy() from - * being called asynchronously if the device is removed. - */ - - priv->crefs++; - DEBUGASSERT(priv->crefs == 2); - - /* Start a worker task to poll the USB device. It would be nice to used the - * the NuttX worker thread to do this, but this task needs to wait for events - * and activities on the worker thread should not involve significant waiting. - * Having a dedicated thread is more efficient in this sense, but requires more - * memory resources, primarily for the dedicated stack (CONFIG_HIDKBD_STACKSIZE). - */ - - uvdbg("user_start: Start poll task\n"); - - /* The inputs to a task started by task_create() are very awkard for this - * purpose. They are really designed for command line tasks (argc/argv). So - * the following is kludge pass binary data when the keyboard poll task - * is started. - * - * First, make sure we have exclusive access to g_priv (what is the likelihood - * of this being used? About zero, but we protect it anyway). - */ - - usbhost_takesem(&g_exclsem); - g_priv = priv; - -#ifndef CONFIG_CUSTOM_STACK - priv->pollpid = task_create("usbhost", CONFIG_HIDKBD_DEFPRIO, - CONFIG_HIDKBD_STACKSIZE, - (main_t)usbhost_kbdpoll, (const char **)NULL); -#else - priv->pollpid = task_create("usbhost", CONFIG_HIDKBD_DEFPRIO, - (main_t)usbhost_kbdpoll, (const char **)NULL); -#endif - if (priv->pollpid == ERROR) - { - /* Failed to started the poll thread... probably due to memory resources */ - - usbhost_givesem(&g_exclsem); - ret = -ENOMEM; - goto errout; - } - - /* Now wait for the poll task to get properly initialized */ - - usbhost_takesem(&g_syncsem); - usbhost_givesem(&g_exclsem); - - /* Register the driver */ - - uvdbg("Register driver\n"); - usbhost_mkdevname(priv, devname); - ret = register_driver(devname, &usbhost_fops, 0666, priv); - - /* We now have to be concerned about asynchronous modification of crefs - * because the driver has been registerd. - */ - -errout: - usbhost_takesem(&priv->exclsem); - priv->crefs--; - usbhost_givesem(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: usbhost_getle16 - * - * Description: - * Get a (possibly unaligned) 16-bit little endian value. - * - * Input Parameters: - * val - A pointer to the first byte of the little endian value. - * - * Returned Values: - * A uint16_t representing the whole 16-bit integer value - * - ****************************************************************************/ - -static inline uint16_t usbhost_getle16(const uint8_t *val) -{ - return (uint16_t)val[1] << 8 | (uint16_t)val[0]; -} - -/**************************************************************************** - * Name: usbhost_putle16 - * - * Description: - * Put a (possibly unaligned) 16-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the little endian value. - * val - The 16-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putle16(uint8_t *dest, uint16_t val) -{ - dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */ - dest[1] = val >> 8; -} - -/**************************************************************************** - * Name: usbhost_getle32 - * - * Description: - * Get a (possibly unaligned) 32-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the big endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline uint32_t usbhost_getle32(const uint8_t *val) -{ - /* Little endian means LS halfword first in byte stream */ - - return (uint32_t)usbhost_getle16(&val[2]) << 16 | (uint32_t)usbhost_getle16(val); -} - -/**************************************************************************** - * Name: usbhost_putle32 - * - * Description: - * Put a (possibly unaligned) 32-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the little endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -#if 0 /* Not used */ -static void usbhost_putle32(uint8_t *dest, uint32_t val) -{ - /* Little endian means LS halfword first in byte stream */ - - usbhost_putle16(dest, (uint16_t)(val & 0xffff)); - usbhost_putle16(dest+2, (uint16_t)(val >> 16)); -} -#endif - -/**************************************************************************** - * Name: usbhost_tdalloc - * - * Description: - * Allocate transfer buffer memory. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * On sucess, zero (OK) is returned. On failure, an negated errno value - * is returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv) -{ - DEBUGASSERT(priv && priv->tbuffer == NULL); - return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen); -} - -/**************************************************************************** - * Name: usbhost_tdfree - * - * Description: - * Free transfer buffer memory. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * On sucess, zero (OK) is returned. On failure, an negated errno value - * is returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv) -{ - int result = OK; - DEBUGASSERT(priv); - - if (priv->tbuffer) - { - DEBUGASSERT(priv->drvr); - result = DRVR_FREE(priv->drvr, priv->tbuffer); - priv->tbuffer = NULL; - priv->tbuflen = 0; - } - return result; -} - -/**************************************************************************** - * struct usbhost_registry_s methods - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_create - * - * Description: - * This function implements the create() method of struct usbhost_registry_s. - * The create() method is a callback into the class implementation. It is - * used to (1) create a new instance of the USB host class state and to (2) - * bind a USB host driver "session" to the class instance. Use of this - * create() method will support environments where there may be multiple - * USB ports and multiple USB devices simultaneously connected. - * - * Input Parameters: - * drvr - An instance of struct usbhost_driver_s that the class - * implementation will "bind" to its state structure and will - * subsequently use to communicate with the USB host driver. - * id - In the case where the device supports multiple base classes, - * subclasses, or protocols, this specifies which to configure for. - * - * Returned Values: - * On success, this function will return a non-NULL instance of struct - * usbhost_class_s that can be used by the USB host driver to communicate - * with the USB host class. NULL is returned on failure; this function - * will fail only if the drvr input parameter is NULL or if there are - * insufficient resources to create another USB host class instance. - * - ****************************************************************************/ - -static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id) -{ - FAR struct usbhost_state_s *priv; - - /* Allocate a USB host class instance */ - - priv = usbhost_allocclass(); - if (priv) - { - /* Initialize the allocated storage class instance */ - - memset(priv, 0, sizeof(struct usbhost_state_s)); - - /* Assign a device number to this class instance */ - - if (usbhost_allocdevno(priv) == OK) - { - /* Initialize class method function pointers */ - - priv->class.connect = usbhost_connect; - priv->class.disconnected = usbhost_disconnected; - - /* The initial reference count is 1... One reference is held by the driver */ - - priv->crefs = 1; - - /* Initialize semaphores */ - - sem_init(&priv->exclsem, 0, 1); - sem_init(&priv->waitsem, 0, 0); - - /* Bind the driver to the storage class instance */ - - priv->drvr = drvr; - - /* Return the instance of the USB keyboard class driver */ - - return &priv->class; - } - } - - /* An error occurred. Free the allocation and return NULL on all failures */ - - if (priv) - { - usbhost_freeclass(priv); - } - return NULL; -} - -/**************************************************************************** - * struct usbhost_class_s methods - ****************************************************************************/ -/**************************************************************************** - * Name: usbhost_connect - * - * Description: - * This function implements the connect() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to provide the device's configuration - * descriptor to the class so that the class may initialize properly - * - * Input Parameters: - * class - The USB host class entry previously obtained from a call to create(). - * configdesc - A pointer to a uint8_t buffer container the configuration descripor. - * desclen - The length in bytes of the configuration descriptor. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * NOTE that the class instance remains valid upon return with a failure. It is - * the responsibility of the higher level enumeration logic to call - * CLASS_DISCONNECTED to free up the class driver resources. - * - * Assumptions: - * - This function will *not* be called from an interrupt handler. - * - If this function returns an error, the USB host controller driver - * must call to DISCONNECTED method to recover from the error - * - ****************************************************************************/ - -static int usbhost_connect(FAR struct usbhost_class_s *class, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class; - int ret; - - DEBUGASSERT(priv != NULL && - configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); - - /* Parse the configuration descriptor to get the endpoints */ - - ret = usbhost_cfgdesc(priv, configdesc, desclen, funcaddr); - if (ret != OK) - { - udbg("usbhost_cfgdesc() failed: %d\n", ret); - } - else - { - /* Now configure the device and register the NuttX driver */ - - ret = usbhost_devinit(priv); - if (ret != OK) - { - udbg("usbhost_devinit() failed: %d\n", ret); - } - } - - /* ERROR handling: Do nothing. If we return and error during connection, - * the driver is required to call the DISCONNECT method. Possibilities: - * - * - Failure occurred before the kbdpoll task was started successfully. - * In this case, the disconnection will have to be handled on the worker - * task. - * - Failure occured after the kbdpoll task was started succesffuly. In - * this case, the disconnetion can be performed on the kbdpoll thread. - */ - - return ret; -} - -/**************************************************************************** - * Name: usbhost_disconnected - * - * Description: - * This function implements the disconnected() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to inform the class that the USB device has - * been disconnected. - * - * Input Parameters: - * class - The USB host class entry previously obtained from a call to - * create(). - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value - * is returned indicating the nature of the failure - * - * Assumptions: - * This function may be called from an interrupt handler. - * - ****************************************************************************/ - -static int usbhost_disconnected(struct usbhost_class_s *class) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class; - - DEBUGASSERT(priv != NULL); - - /* Set an indication to any users of the keyboard device that the device - * is no longer available. - */ - - priv->disconnected = true; - ullvdbg("Disconnected\n"); - - /* Is there a thread waiting for keyboard data that will never come? */ - - if (priv->waiting) - { - /* Yes.. wake it up */ - - usbhost_givesem(&priv->waitsem); - priv->waiting = false; - } - - /* Possibilities: - * - * - Failure occurred before the kbdpoll task was started successfully. - * In this case, the disconnection will have to be handled on the worker - * task. - * - Failure occured after the kbdpoll task was started succesffuly. In - * this case, the disconnetion can be performed on the kbdpoll thread. - */ - - if (priv->polling) - { - /* The polling task is still alive. Signal the keyboard polling task. - * When that task wakes up, it will decrement the reference count and, - * perhaps, destroy the class instance. Then it will exit. - */ - - (void)kill(priv->pollpid, SIGALRM); - } - else - { - /* In the case where the failure occurs before the polling task was - * started. Now what? We are probably executing from an interrupt - * handler here. We will use the worker thread. This is kind of - * wasteful and begs for a re-design. - */ - - DEBUGASSERT(priv->work.worker == NULL); - (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0); - } - - return OK; -} - -/**************************************************************************** - * Character driver methods - ****************************************************************************/ -/**************************************************************************** - * Name: usbhost_open - * - * Description: - * Standard character driver open method. - * - ****************************************************************************/ - -static int usbhost_open(FAR struct file *filep) -{ - FAR struct inode *inode; - FAR struct usbhost_state_s *priv; - irqstate_t flags; - int ret; - - uvdbg("Entry\n"); - DEBUGASSERT(filep && filep->f_inode); - inode = filep->f_inode; - priv = inode->i_private; - - /* Make sure that we have exclusive access to the private data structure */ - - DEBUGASSERT(priv && priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS); - usbhost_takesem(&priv->exclsem); - - /* Check if the keyboard device is still connected. We need to disable - * interrupts momentarily to assure that there are no asynchronous disconnect - * events. - */ - - flags = irqsave(); - if (priv->disconnected) - { - /* No... the driver is no longer bound to the class. That means that - * the USB storage device is no longer connected. Refuse any further - * attempts to open the driver. - */ - - ret = -ENODEV; - } - else - { - /* Otherwise, just increment the reference count on the driver */ - - priv->crefs++; - priv->open = true; - ret = OK; - } - irqrestore(flags); - - usbhost_givesem(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: usbhost_close - * - * Description: - * Standard character driver close method. - * - ****************************************************************************/ - -static int usbhost_close(FAR struct file *filep) -{ - FAR struct inode *inode; - FAR struct usbhost_state_s *priv; - - uvdbg("Entry\n"); - DEBUGASSERT(filep && filep->f_inode); - inode = filep->f_inode; - priv = inode->i_private; - - /* Decrement the reference count on the driver */ - - DEBUGASSERT(priv->crefs > 1); - usbhost_takesem(&priv->exclsem); - priv->crefs--; - - /* Is this the last reference (other than the one held by the USB host - * controller driver) - */ - - if (priv->crefs <= 1) - { - irqstate_t flags; - - /* Yes.. then the driver is no longer open */ - - priv->open = false; - priv->headndx = 0; - priv->tailndx = 0; - - /* We need to disable interrupts momentarily to assure that there are - * no asynchronous disconnect events. - */ - - flags = irqsave(); - - /* Check if the USB keyboard device is still connected. If the device is - * no longer connected, then unregister the driver and free the driver - * class instance. - */ - - if (priv->disconnected) - { - /* Destroy the class instance (we can't use priv after this; we can't - * 'give' the semapore) - */ - - usbhost_destroy(priv); - irqrestore(flags); - return OK; - } - irqrestore(flags); - } - - usbhost_givesem(&priv->exclsem); - return OK; -} - -/**************************************************************************** - * Name: usbhost_read - * - * Description: - * Standard character driver read method. - * - ****************************************************************************/ - -static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct usbhost_state_s *priv; - size_t nbytes; - unsigned int tail; - int ret; - - uvdbg("Entry\n"); - DEBUGASSERT(filep && filep->f_inode && buffer); - inode = filep->f_inode; - priv = inode->i_private; - - /* Make sure that we have exclusive access to the private data structure */ - - DEBUGASSERT(priv && priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS); - usbhost_takesem(&priv->exclsem); - - /* Check if the keyboard is still connected. We need to disable interrupts - * momentarily to assure that there are no asynchronous disconnect events. - */ - - if (priv->disconnected) - { - /* No... the driver is no longer bound to the class. That means that - * the USB keybaord is no longer connected. Refuse any further attempts - * to access the driver. - */ - - ret = -ENODEV; - } - else - { - /* Is there keyboard data now? */ - - while (priv->tailndx == priv->headndx) - { - /* No.. were we open non-blocking? */ - - if (filep->f_oflags & O_NONBLOCK) - { - /* Yes.. then return a failure */ - - ret = -EAGAIN; - goto errout; - } - - /* Wait for data to be available */ - - uvdbg("Waiting...\n"); - - priv->waiting = true; - usbhost_givesem(&priv->exclsem); - usbhost_takesem(&priv->waitsem); - usbhost_takesem(&priv->exclsem); - - /* Did the keyboard become disconnected while we were waiting */ - - if (priv->disconnected) - { - ret = -ENODEV; - goto errout; - } - } - - /* Read data from our internal buffer of received characters */ - - for (tail = priv->tailndx, nbytes = 0; - tail != priv->headndx && nbytes < len; - nbytes++) - { - /* Copy the next keyboard character into the user buffer */ - - *buffer++ = priv->kbdbuffer[tail]; - - /* Handle wrap-around of the tail index */ - - if (++tail >= CONFIG_HIDKBD_BUFSIZE) - { - tail = 0; - } - } - ret = nbytes; - - /* Update the tail index (pehaps marking the buffer empty) */ - - priv->tailndx = tail; - } - -errout: - usbhost_givesem(&priv->exclsem); - return (ssize_t)ret; -} - -/**************************************************************************** - * Name: usbhost_write - * - * Description: - * Standard character driver write method. - * - ****************************************************************************/ - -static ssize_t usbhost_write(FAR struct file *filep, FAR const char *buffer, size_t len) -{ - /* We won't try to write to the keyboard */ - - return -ENOSYS; -} - -/**************************************************************************** - * Name: usbhost_poll - * - * Description: - * Standard character driver poll method. - * - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct usbhost_state_s *priv; - int ret = OK; - int i; - - uvdbg("Entry\n"); - DEBUGASSERT(filep && filep->f_inode && fds); - inode = filep->f_inode; - priv = inode->i_private; - - /* Make sure that we have exclusive access to the private data structure */ - - DEBUGASSERT(priv); - usbhost_takesem(&priv->exclsem); - - /* Check if the keyboard is still connected. We need to disable interrupts - * momentarily to assure that there are no asynchronous disconnect events. - */ - - if (priv->disconnected) - { - /* No... the driver is no longer bound to the class. That means that - * the USB keybaord is no longer connected. Refuse any further attempts - * to access the driver. - */ - - ret = -ENODEV; - } - else if (setup) - { - /* This is a request to set up the poll. Find an availableslot for - * the poll structure reference - */ - - for (i = 0; i < CONFIG_HIDKBD_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_HIDKBD_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? Notify - * the POLLIN event if there is buffered keyboard data. - */ - - if (priv->headndx != priv->tailndx) - { - usbhost_pollnotify(priv); - } - } - else - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->exclsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_kbdinit - * - * Description: - * Initialize the USB storage HID keyboard class driver. This function - * should be called be platform-specific code in order to initialize and - * register support for the USB host HID keyboard class device. - * - * Input Parameters: - * None - * - * Returned Values: - * On success this function will return zero (OK); A negated errno value - * will be returned on failure. - * - ****************************************************************************/ - -int usbhost_kbdinit(void) -{ - /* Perform any one-time initialization of the class implementation */ - - sem_init(&g_exclsem, 0, 1); - sem_init(&g_syncsem, 0, 0); - - /* Advertise our availability to support (certain) devices */ - - return usbhost_registerclass(&g_skeleton); -} - -#endif /* CONFIG_USBHOST)&& !CONFIG_USBHOST_INT_DISABLE && CONFIG_NFILE_DESCRIPTORS */ - - diff --git a/nuttx/drivers/usbhost/usbhost_registerclass.c b/nuttx/drivers/usbhost/usbhost_registerclass.c deleted file mode 100644 index f4d1b64af..000000000 --- a/nuttx/drivers/usbhost/usbhost_registerclass.c +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/usbhost_registerclass.c - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -#include "usbhost_registry.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_registerclass - * - * Description: - * Register a USB host class implementation. The caller provides an - * instance of struct usbhost_registry_s that contains all of the - * information that will be needed later to (1) associate the USB host - * class implementation with a connected USB device, and (2) to obtain and - * bind a struct usbhost_class_s instance for the device. - * - * Input Parameters: - * class - An write-able instance of struct usbhost_registry_s that will be - * maintained in a registry. - * - * Returned Values: - * On success, this function will return zero (OK). Otherwise, a negated - * errno value is returned. - * - ****************************************************************************/ - -int usbhost_registerclass(struct usbhost_registry_s *class) -{ - irqstate_t flags; - - uvdbg("Registering class:%p nids:%d\n", class, class->nids); - - /* g_classregistry is a singly-linkedlist of class ID information added by - * calls to usbhost_registerclass(). Since this list is accessed from USB - * host controller interrupt handling logic, accesses to this list must be - * protected by disabling interrupts. - */ - - flags = irqsave(); - - /* Add the new class ID info to the head of the list */ - - class->flink = g_classregistry; - g_classregistry = class; - - irqrestore(flags); - return OK; -} - diff --git a/nuttx/drivers/usbhost/usbhost_registry.c b/nuttx/drivers/usbhost/usbhost_registry.c deleted file mode 100644 index fb2e900e2..000000000 --- a/nuttx/drivers/usbhost/usbhost_registry.c +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/usbhost_registry.c - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include "usbhost_registry.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/* g_classregistry is a singly-linkedlist of class ID information added by - * calls to usbhost_registerclass(). Since this list is accessed from USB - * host controller interrupt handling logic, accesses to this list must be - * protected by disabling interrupts. - */ - -struct usbhost_registry_s *g_classregistry; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ diff --git a/nuttx/drivers/usbhost/usbhost_registry.h b/nuttx/drivers/usbhost/usbhost_registry.h deleted file mode 100644 index 759a1c66e..000000000 --- a/nuttx/drivers/usbhost/usbhost_registry.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/usbdev_registry.h - * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __DRIVERS_USBHOST_USBHOST_REGISTRY_H -#define __DRIVERS_USBHOST_USBHOST_REGISTRY_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -# define EXTERN extern "C" -extern "C" -{ -#else -# define EXTERN extern -#endif - -/* g_classregistry is a singly-linkedlist of class ID information added by - * calls to usbhost_registerclass(). Since this list is accessed from USB - * host controller interrupt handling logic, accesses to this list must be - * protected by disabling interrupts. - */ - -EXTERN struct usbhost_registry_s *g_classregistry; - -/************************************************************************************ - * Public Function Prototypes - ************************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -} -#endif - -#endif /* #define __DRIVERS_USBHOST_USBHOST_REGISTRY_H */ diff --git a/nuttx/drivers/usbhost/usbhost_skeleton.c b/nuttx/drivers/usbhost/usbhost_skeleton.c deleted file mode 100644 index c44a265e8..000000000 --- a/nuttx/drivers/usbhost/usbhost_skeleton.c +++ /dev/null @@ -1,1060 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/usbhost_skeleton.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -#ifndef CONFIG_SCHED_WORKQUEUE -# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" -#endif - -/* Driver support ***********************************************************/ -/* This format is used to construct the /dev/skel[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/skel%c" -#define DEV_NAMELEN 12 - -/* Used in usbhost_cfgdesc() */ - -#define USBHOST_IFFOUND 0x01 -#define USBHOST_BINFOUND 0x02 -#define USBHOST_BOUTFOUND 0x04 -#define USBHOST_ALLFOUND 0x07 - -#define USBHOST_MAX_CREFS 0x7fff - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure contains the internal, private state of the USB host class - * driver. - */ - -struct usbhost_state_s -{ - /* This is the externally visible portion of the state */ - - struct usbhost_class_s class; - - /* This is an instance of the USB host driver bound to this class instance */ - - struct usbhost_driver_s *drvr; - - /* The remainder of the fields are provide to the class driver */ - - char devchar; /* Character identifying the /dev/skel[n] device */ - volatile bool disconnected; /* TRUE: Device has been disconnected */ - uint8_t ifno; /* Interface number */ - int16_t crefs; /* Reference count on the driver instance */ - sem_t exclsem; /* Used to maintain mutual exclusive access */ - struct work_s work; /* For interacting with the worker thread */ - FAR uint8_t *tbuffer; /* The allocated transfer buffer */ - size_t tbuflen; /* Size of the allocated transfer buffer */ - usbhost_ep_t epin; /* IN endpoint */ - usbhost_ep_t epout; /* OUT endpoint */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Semaphores */ - -static void usbhost_takesem(sem_t *sem); -#define usbhost_givesem(s) sem_post(s); - -/* Memory allocation services */ - -static inline FAR struct usbhost_state_s *usbhost_allocclass(void); -static inline void usbhost_freeclass(FAR struct usbhost_state_s *class); - -/* Device name management */ - -static int usbhost_allocdevno(FAR struct usbhost_state_s *priv); -static void usbhost_freedevno(FAR struct usbhost_state_s *priv); -static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname); - -/* Worker thread actions */ - -static void usbhost_destroy(FAR void *arg); - -/* Helpers for usbhost_connect() */ - -static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr); -static inline int usbhost_devinit(FAR struct usbhost_state_s *priv); - -/* (Little Endian) Data helpers */ - -static inline uint16_t usbhost_getle16(const uint8_t *val); -static inline void usbhost_putle16(uint8_t *dest, uint16_t val); -static inline uint32_t usbhost_getle32(const uint8_t *val); -static void usbhost_putle32(uint8_t *dest, uint32_t val); - -/* Transfer descriptor memory management */ - -static inline int usbhost_talloc(FAR struct usbhost_state_s *priv); -static inline int usbhost_tfree(FAR struct usbhost_state_s *priv); - -/* struct usbhost_registry_s methods */ - -static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id); - -/* struct usbhost_class_s methods */ - -static int usbhost_connect(FAR struct usbhost_class_s *class, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr); -static int usbhost_disconnected(FAR struct usbhost_class_s *class); - -/* Driver methods -- depend upon the type of NuttX driver interface exported */ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This structure provides the registry entry ID informatino that will be - * used to associate the USB class driver to a connected USB device. - */ - -static const const struct usbhost_id_s g_id = -{ - 0, /* base -- Must be one of the USB_CLASS_* definitions in usb.h */ - 0, /* subclass -- depends on the device */ - 0, /* proto -- depends on the device */ - 0, /* vid */ - 0 /* pid */ -}; - -/* This is the USB host storage class's registry entry */ - -static struct usbhost_registry_s g_skeleton = -{ - NULL, /* flink */ - usbhost_create, /* create */ - 1, /* nids */ - &g_id /* id[] */ -}; - -/* This is a bitmap that is used to allocate device names /dev/skela-z. */ - -static uint32_t g_devinuse; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_takesem - * - * Description: - * This is just a wrapper to handle the annoying behavior of semaphore - * waits that return due to the receipt of a signal. - * - ****************************************************************************/ - -static void usbhost_takesem(sem_t *sem) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(sem) != 0) - { - /* The only case that an error should occr here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -/**************************************************************************** - * Name: usbhost_allocclass - * - * Description: - * This is really part of the logic that implements the create() method - * of struct usbhost_registry_s. This function allocates memory for one - * new class instance. - * - * Input Parameters: - * None - * - * Returned Values: - * On success, this function will return a non-NULL instance of struct - * usbhost_class_s. NULL is returned on failure; this function will - * will fail only if there are insufficient resources to create another - * USB host class instance. - * - ****************************************************************************/ - -static inline FAR struct usbhost_state_s *usbhost_allocclass(void) -{ - FAR struct usbhost_state_s *priv; - - DEBUGASSERT(!up_interrupt_context()); - priv = (FAR struct usbhost_state_s *)kmalloc(sizeof(struct usbhost_state_s)); - uvdbg("Allocated: %p\n", priv);; - return priv; -} - -/**************************************************************************** - * Name: usbhost_freeclass - * - * Description: - * Free a class instance previously allocated by usbhost_allocclass(). - * - * Input Parameters: - * class - A reference to the class instance to be freed. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline void usbhost_freeclass(FAR struct usbhost_state_s *class) -{ - DEBUGASSERT(class != NULL); - - /* Free the class instance (perhaps calling sched_free() in case we are - * executing from an interrupt handler. - */ - - uvdbg("Freeing: %p\n", class);; - kfree(class); -} - -/**************************************************************************** - * Name: Device name management - * - * Description: - * Some tiny functions to coordinate management of device names. - * - ****************************************************************************/ - -static int usbhost_allocdevno(FAR struct usbhost_state_s *priv) -{ - irqstate_t flags; - int devno; - - flags = irqsave(); - for (devno = 0; devno < 26; devno++) - { - uint32_t bitno = 1 << devno; - if ((g_devinuse & bitno) == 0) - { - g_devinuse |= bitno; - priv->devchar = 'a' + devno; - irqrestore(flags); - return OK; - } - } - - irqrestore(flags); - return -EMFILE; -} - -static void usbhost_freedevno(FAR struct usbhost_state_s *priv) -{ - int devno = 'a' - priv->devchar; - - if (devno >= 0 && devno < 26) - { - irqstate_t flags = irqsave(); - g_devinuse &= ~(1 << devno); - irqrestore(flags); - } -} - -static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname) -{ - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar); -} - -/**************************************************************************** - * Name: usbhost_destroy - * - * Description: - * The USB device has been disconnected and the refernce count on the USB - * host class instance has gone to 1.. Time to destroy the USB host class - * instance. - * - * Input Parameters: - * arg - A reference to the class instance to be destroyed. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_destroy(FAR void *arg) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg; - - DEBUGASSERT(priv != NULL); - uvdbg("crefs: %d\n", priv->crefs); - - /* Unregister the driver */ - - /* Release the device name used by this connection */ - - usbhost_freedevno(priv); - - /* Free the endpoints */ - - /* Free any transfer buffers */ - - /* Destroy the semaphores */ - - /* Disconnect the USB host device */ - - DRVR_DISCONNECT(priv->drvr); - - /* And free the class instance. Hmmm.. this may execute on the worker - * thread and the work structure is part of what is getting freed. That - * should be okay because once the work contained is removed from the - * queue, it should not longer be accessed by the worker thread. - */ - - usbhost_freeclass(priv); -} - -/**************************************************************************** - * Name: usbhost_cfgdesc - * - * Description: - * This function implements the connect() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to provide the device's configuration - * descriptor to the class so that the class may initialize properly - * - * Input Parameters: - * priv - The USB host class instance. - * configdesc - A pointer to a uint8_t buffer container the configuration descripor. - * desclen - The length in bytes of the configuration descriptor. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * Assumptions: - * This function will *not* be called from an interrupt handler. - * - ****************************************************************************/ - -static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr) -{ - FAR struct usb_cfgdesc_s *cfgdesc; - FAR struct usb_desc_s *desc; - FAR struct usbhost_epdesc_s bindesc; - FAR struct usbhost_epdesc_s boutdesc; - int remaining; - uint8_t found = 0; - int ret; - - DEBUGASSERT(priv != NULL && - configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); - - /* Verify that we were passed a configuration descriptor */ - - cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc; - if (cfgdesc->type != USB_DESC_TYPE_CONFIG) - { - return -EINVAL; - } - - /* Get the total length of the configuration descriptor (little endian). - * It might be a good check to get the number of interfaces here too. - */ - - remaining = (int)usbhost_getle16(cfgdesc->totallen); - - /* Skip to the next entry descriptor */ - - configdesc += cfgdesc->len; - remaining -= cfgdesc->len; - - /* Loop where there are more dscriptors to examine */ - - while (remaining >= sizeof(struct usb_desc_s)) - { - /* What is the next descriptor? */ - - desc = (FAR struct usb_desc_s *)configdesc; - switch (desc->type) - { - /* Interface descriptor. We really should get the number of endpoints - * from this descriptor too. - */ - - case USB_DESC_TYPE_INTERFACE: - { - FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc; - - uvdbg("Interface descriptor\n"); - DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC); - - /* Save the interface number and mark ONLY the interface found */ - - priv->ifno = ifdesc->ifno; - found = USBHOST_IFFOUND; - } - break; - - /* Endpoint descriptor. Here, we expect two bulk endpoints, an IN - * and an OUT. - */ - - case USB_DESC_TYPE_ENDPOINT: - { - FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc; - - uvdbg("Endpoint descriptor\n"); - DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC); - - /* Check for a bulk endpoint. */ - - if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_BULK) - { - /* Yes.. it is a bulk endpoint. IN or OUT? */ - - if (USB_ISEPOUT(epdesc->addr)) - { - /* It is an OUT bulk endpoint. There should be only one - * bulk OUT endpoint. - */ - - if ((found & USBHOST_BOUTFOUND) != 0) - { - /* Oops.. more than one endpoint. We don't know - * what to do with this. - */ - - return -EINVAL; - } - found |= USBHOST_BOUTFOUND; - - /* Save the bulk OUT endpoint information */ - - boutdesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; - boutdesc.in = false; - boutdesc.funcaddr = funcaddr; - boutdesc.xfrtype = USB_EP_ATTR_XFER_BULK; - boutdesc.interval = epdesc->interval; - boutdesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); - uvdbg("Bulk OUT EP addr:%d mxpacketsize:%d\n", - boutdesc.addr, boutdesc.mxpacketsize); - } - else - { - /* It is an IN bulk endpoint. There should be only one - * bulk IN endpoint. - */ - - if ((found & USBHOST_BINFOUND) != 0) - { - /* Oops.. more than one endpoint. We don't know - * what to do with this. - */ - - return -EINVAL; - } - found |= USBHOST_BINFOUND; - - /* Save the bulk IN endpoint information */ - - bindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; - bindesc.in = 1; - bindesc.funcaddr = funcaddr; - bindesc.xfrtype = USB_EP_ATTR_XFER_BULK; - bindesc.interval = epdesc->interval; - bindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); - uvdbg("Bulk IN EP addr:%d mxpacketsize:%d\n", - bindesc.addr, bindesc.mxpacketsize); - } - } - } - break; - - /* Other descriptors are just ignored for now */ - - default: - break; - } - - /* If we found everything we need with this interface, then break out - * of the loop early. - */ - - if (found == USBHOST_ALLFOUND) - { - break; - } - - /* Increment the address of the next descriptor */ - - configdesc += desc->len; - remaining -= desc->len; - } - - /* Sanity checking... did we find all of things that we need? */ - - if (found != USBHOST_ALLFOUND) - { - ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n", - (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO", - (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO", - (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO"); - return -EINVAL; - } - - /* We are good... Allocate the endpoints */ - - ret = DRVR_EPALLOC(priv->drvr, &boutdesc, &priv->epout); - if (ret != OK) - { - udbg("ERROR: Failed to allocate Bulk OUT endpoint\n"); - return ret; - } - - ret = DRVR_EPALLOC(priv->drvr, &bindesc, &priv->epin); - if (ret != OK) - { - udbg("ERROR: Failed to allocate Bulk IN endpoint\n"); - (void)DRVR_EPFREE(priv->drvr, priv->epout); - return ret; - } - - ullvdbg("Endpoints allocated\n"); - return OK; -} - -/**************************************************************************** - * Name: usbhost_devinit - * - * Description: - * The USB device has been successfully connected. This completes the - * initialization operations. It is first called after the - * configuration descriptor has been received. - * - * This function is called from the connect() method. This function always - * executes on the thread of the caller of connect(). - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline int usbhost_devinit(FAR struct usbhost_state_s *priv) -{ - int ret = OK; - - /* Set aside a transfer buffer for exclusive use by the class driver */ - - /* Increment the reference count. This will prevent usbhost_destroy() from - * being called asynchronously if the device is removed. - */ - - priv->crefs++; - DEBUGASSERT(priv->crefs == 2); - - /* Configure the device */ - - /* Register the driver */ - - if (ret == OK) - { - char devname[DEV_NAMELEN]; - - uvdbg("Register block driver\n"); - usbhost_mkdevname(priv, devname); - // ret = register_blockdriver(devname, &g_bops, 0, priv); - } - - /* Check if we successfully initialized. We now have to be concerned - * about asynchronous modification of crefs because the block - * driver has been registerd. - */ - - if (ret == OK) - { - usbhost_takesem(&priv->exclsem); - DEBUGASSERT(priv->crefs >= 2); - - /* Handle a corner case where (1) open() has been called so the - * reference count is > 2, but the device has been disconnected. - * In this case, the class instance needs to persist until close() - * is called. - */ - - if (priv->crefs <= 2 && priv->disconnected) - { - /* We don't have to give the semaphore because it will be - * destroyed when usb_destroy is called. - */ - - ret = -ENODEV; - } - else - { - /* Ready for normal operation as a block device driver */ - - uvdbg("Successfully initialized\n"); - priv->crefs--; - usbhost_givesem(&priv->exclsem); - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbhost_getle16 - * - * Description: - * Get a (possibly unaligned) 16-bit little endian value. - * - * Input Parameters: - * val - A pointer to the first byte of the little endian value. - * - * Returned Values: - * A uint16_t representing the whole 16-bit integer value - * - ****************************************************************************/ - -static inline uint16_t usbhost_getle16(const uint8_t *val) -{ - return (uint16_t)val[1] << 8 | (uint16_t)val[0]; -} - -/**************************************************************************** - * Name: usbhost_putle16 - * - * Description: - * Put a (possibly unaligned) 16-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the little endian value. - * val - The 16-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putle16(uint8_t *dest, uint16_t val) -{ - dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */ - dest[1] = val >> 8; -} - -/**************************************************************************** - * Name: usbhost_getle32 - * - * Description: - * Get a (possibly unaligned) 32-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the big endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline uint32_t usbhost_getle32(const uint8_t *val) -{ - /* Little endian means LS halfword first in byte stream */ - - return (uint32_t)usbhost_getle16(&val[2]) << 16 | (uint32_t)usbhost_getle16(val); -} - -/**************************************************************************** - * Name: usbhost_putle32 - * - * Description: - * Put a (possibly unaligned) 32-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the little endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putle32(uint8_t *dest, uint32_t val) -{ - /* Little endian means LS halfword first in byte stream */ - - usbhost_putle16(dest, (uint16_t)(val & 0xffff)); - usbhost_putle16(dest+2, (uint16_t)(val >> 16)); -} - -/**************************************************************************** - * Name: usbhost_talloc - * - * Description: - * Allocate transfer buffer memory. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * On sucess, zero (OK) is returned. On failure, an negated errno value - * is returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static inline int usbhost_talloc(FAR struct usbhost_state_s *priv) -{ - DEBUGASSERT(priv && priv->tbuffer == NULL); - return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen); -} - -/**************************************************************************** - * Name: usbhost_tfree - * - * Description: - * Free transfer buffer memory. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * On sucess, zero (OK) is returned. On failure, an negated errno value - * is returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static inline int usbhost_tfree(FAR struct usbhost_state_s *priv) -{ - int result = OK; - DEBUGASSERT(priv); - - if (priv->tbuffer) - { - DEBUGASSERT(priv->drvr); - result = DRVR_FREE(priv->drvr, priv->tbuffer); - priv->tbuffer = NULL; - priv->tbuflen = 0; - } - return result; -} - -/**************************************************************************** - * struct usbhost_registry_s methods - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_create - * - * Description: - * This function implements the create() method of struct usbhost_registry_s. - * The create() method is a callback into the class implementation. It is - * used to (1) create a new instance of the USB host class state and to (2) - * bind a USB host driver "session" to the class instance. Use of this - * create() method will support environments where there may be multiple - * USB ports and multiple USB devices simultaneously connected. - * - * Input Parameters: - * drvr - An instance of struct usbhost_driver_s that the class - * implementation will "bind" to its state structure and will - * subsequently use to communicate with the USB host driver. - * id - In the case where the device supports multiple base classes, - * subclasses, or protocols, this specifies which to configure for. - * - * Returned Values: - * On success, this function will return a non-NULL instance of struct - * usbhost_class_s that can be used by the USB host driver to communicate - * with the USB host class. NULL is returned on failure; this function - * will fail only if the drvr input parameter is NULL or if there are - * insufficient resources to create another USB host class instance. - * - ****************************************************************************/ - -static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id) -{ - FAR struct usbhost_state_s *priv; - - /* Allocate a USB host class instance */ - - priv = usbhost_allocclass(); - if (priv) - { - /* Initialize the allocated storage class instance */ - - memset(priv, 0, sizeof(struct usbhost_state_s)); - - /* Assign a device number to this class instance */ - - if (usbhost_allocdevno(priv) == OK) - { - /* Initialize class method function pointers */ - - priv->class.connect = usbhost_connect; - priv->class.disconnected = usbhost_disconnected; - - /* The initial reference count is 1... One reference is held by the driver */ - - priv->crefs = 1; - - /* Initialize semphores (this works okay in the interrupt context) */ - - sem_init(&priv->exclsem, 0, 1); - - /* Bind the driver to the storage class instance */ - - priv->drvr = drvr; - - /* Return the instance of the USB class driver */ - - return &priv->class; - } - } - - /* An error occurred. Free the allocation and return NULL on all failures */ - - if (priv) - { - usbhost_freeclass(priv); - } - return NULL; -} - -/**************************************************************************** - * struct usbhost_class_s methods - ****************************************************************************/ -/**************************************************************************** - * Name: usbhost_connect - * - * Description: - * This function implements the connect() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to provide the device's configuration - * descriptor to the class so that the class may initialize properly - * - * Input Parameters: - * class - The USB host class entry previously obtained from a call to create(). - * configdesc - A pointer to a uint8_t buffer container the configuration descripor. - * desclen - The length in bytes of the configuration descriptor. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * NOTE that the class instance remains valid upon return with a failure. It is - * the responsibility of the higher level enumeration logic to call - * CLASS_DISCONNECTED to free up the class driver resources. - * - * Assumptions: - * - This function will *not* be called from an interrupt handler. - * - If this function returns an error, the USB host controller driver - * must call to DISCONNECTED method to recover from the error - * - ****************************************************************************/ - -static int usbhost_connect(FAR struct usbhost_class_s *class, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class; - int ret; - - DEBUGASSERT(priv != NULL && - configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); - - /* Parse the configuration descriptor to get the endpoints */ - - ret = usbhost_cfgdesc(priv, configdesc, desclen, funcaddr); - if (ret != OK) - { - udbg("usbhost_cfgdesc() failed: %d\n", ret); - } - else - { - /* Now configure the device and register the NuttX driver */ - - ret = usbhost_devinit(priv); - if (ret != OK) - { - udbg("usbhost_devinit() failed: %d\n", ret); - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbhost_disconnected - * - * Description: - * This function implements the disconnected() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to inform the class that the USB device has - * been disconnected. - * - * Input Parameters: - * class - The USB host class entry previously obtained from a call to - * create(). - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value - * is returned indicating the nature of the failure - * - * Assumptions: - * This function may be called from an interrupt handler. - * - ****************************************************************************/ - -static int usbhost_disconnected(struct usbhost_class_s *class) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class; - irqstate_t flags; - - DEBUGASSERT(priv != NULL); - - /* Set an indication to any users of the device that the device is no - * longer available. - */ - - flags = irqsave(); - priv->disconnected = true; - - /* Now check the number of references on the class instance. If it is one, - * then we can free the class instance now. Otherwise, we will have to - * wait until the holders of the references free them by closing the - * block driver. - */ - - ullvdbg("crefs: %d\n", priv->crefs); - if (priv->crefs == 1) - { - /* Destroy the class instance. If we are executing from an interrupt - * handler, then defer the destruction to the worker thread. - * Otherwise, destroy the instance now. - */ - - if (up_interrupt_context()) - { - /* Destroy the instance on the worker thread. */ - - uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy); - DEBUGASSERT(priv->work.worker == NULL); - (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0); - } - else - { - /* Do the work now */ - - usbhost_destroy(priv); - } - } - - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_skelinit - * - * Description: - * Initialize the USB class driver. This function should be called - * be platform-specific code in order to initialize and register support - * for the USB host class device. - * - * Input Parameters: - * None - * - * Returned Values: - * On success this function will return zero (OK); A negated errno value - * will be returned on failure. - * - ****************************************************************************/ - -int usbhost_skelinit(void) -{ - /* Perform any one-time initialization of the class implementation */ - - /* Advertise our availability to support (certain) devices */ - - return usbhost_registerclass(&g_skeleton); -} diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c deleted file mode 100644 index 2b14676d7..000000000 --- a/nuttx/drivers/usbhost/usbhost_storage.c +++ /dev/null @@ -1,2244 +0,0 @@ -/**************************************************************************** - * drivers/usbhost/usbhost_storage.c - * - * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Don't compile if prerequisites are not met */ - -#if defined(CONFIG_USBHOST) && !defined(CONFIG_USBHOST_BULK_DISABLE) && \ - !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -#ifndef CONFIG_SCHED_WORKQUEUE -# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" -#endif - -/* If the create() method is called by the USB host device driver from an - * interrupt handler, then it will be unable to call kmalloc() in order to - * allocate a new class instance. If the create() method is called from the - * interrupt level, then class instances must be pre-allocated. - */ - -#ifndef CONFIG_USBHOST_NPREALLOC -# define CONFIG_USBHOST_NPREALLOC 0 -#endif - -#if CONFIG_USBHOST_NPREALLOC > 26 -# error "Currently limited to 26 devices /dev/sda-z" -#endif - -/* Driver support ***********************************************************/ -/* This format is used to construct the /dev/sd[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/sd%c" -#define DEV_NAMELEN 10 - -/* Used in usbhost_connect() */ - -#define USBHOST_IFFOUND 0x01 -#define USBHOST_BINFOUND 0x02 -#define USBHOST_BOUTFOUND 0x04 -#define USBHOST_ALLFOUND 0x07 - -#define USBHOST_MAX_RETRIES 100 -#define USBHOST_MAX_CREFS 0x7fff - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure contains the internal, private state of the USB host mass - * storage class. - */ - -struct usbhost_state_s -{ - /* This is the externally visible portion of the state */ - - struct usbhost_class_s class; - - /* This is an instance of the USB host driver bound to this class instance */ - - struct usbhost_driver_s *drvr; - - /* The remainder of the fields are provide to the mass storage class */ - - char sdchar; /* Character identifying the /dev/sd[n] device */ - volatile bool disconnected; /* TRUE: Device has been disconnected */ - uint8_t ifno; /* Interface number */ - int16_t crefs; /* Reference count on the driver instance */ - uint16_t blocksize; /* Block size of USB mass storage device */ - uint32_t nblocks; /* Number of blocks on the USB mass storage device */ - sem_t exclsem; /* Used to maintain mutual exclusive access */ - struct work_s work; /* For interacting with the worker thread */ - FAR uint8_t *tbuffer; /* The allocated transfer buffer */ - size_t tbuflen; /* Size of the allocated transfer buffer */ - usbhost_ep_t bulkin; /* Bulk IN endpoint */ - usbhost_ep_t bulkout; /* Bulk OUT endpoint */ -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Semaphores */ - -static void usbhost_takesem(sem_t *sem); -#define usbhost_givesem(s) sem_post(s); - -/* Memory allocation services */ - -static inline FAR struct usbhost_state_s *usbhost_allocclass(void); -static inline void usbhost_freeclass(FAR struct usbhost_state_s *class); - -/* Device name management */ - -static int usbhost_allocdevno(FAR struct usbhost_state_s *priv); -static void usbhost_freedevno(FAR struct usbhost_state_s *priv); -static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname); - -/* CBW/CSW debug helpers */ - -#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE) -static void usbhost_dumpcbw(FAR struct usbmsc_cbw_s *cbw); -static void usbhost_dumpcsw(FAR struct usbmsc_csw_s *csw); -#else -# define usbhost_dumpcbw(cbw); -# define usbhost_dumpcsw(csw); -#endif - -/* CBW helpers */ - -static inline void usbhost_requestsensecbw(FAR struct usbmsc_cbw_s *cbw); -static inline void usbhost_testunitreadycbw(FAR struct usbmsc_cbw_s *cbw); -static inline void usbhost_readcapacitycbw(FAR struct usbmsc_cbw_s *cbw); -static inline void usbhost_inquirycbw (FAR struct usbmsc_cbw_s *cbw); -static inline void usbhost_readcbw (size_t startsector, uint16_t blocksize, - unsigned int nsectors, - FAR struct usbmsc_cbw_s *cbw); -static inline void usbhost_writecbw(size_t startsector, uint16_t blocksize, - unsigned int nsectors, - FAR struct usbmsc_cbw_s *cbw); -/* Command helpers */ - -static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv); -static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv); -static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv); -static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv); -static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv); - -/* Worker thread actions */ - -static void usbhost_destroy(FAR void *arg); - -/* Helpers for usbhost_connect() */ - -static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr); -static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv); - -/* (Little Endian) Data helpers */ - -static inline uint16_t usbhost_getle16(const uint8_t *val); -static inline uint16_t usbhost_getbe16(const uint8_t *val); -static inline void usbhost_putle16(uint8_t *dest, uint16_t val); -static inline void usbhost_putbe16(uint8_t *dest, uint16_t val); -static inline uint32_t usbhost_getle32(const uint8_t *val); -static inline uint32_t usbhost_getbe32(const uint8_t *val); -static void usbhost_putle32(uint8_t *dest, uint32_t val); -static void usbhost_putbe32(uint8_t *dest, uint32_t val); - -/* Transfer descriptor memory management */ - -static inline int usbhost_talloc(FAR struct usbhost_state_s *priv); -static inline int usbhost_tfree(FAR struct usbhost_state_s *priv); -static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv); - -/* struct usbhost_registry_s methods */ - -static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id); - -/* struct usbhost_class_s methods */ - -static int usbhost_connect(FAR struct usbhost_class_s *class, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr); -static int usbhost_disconnected(FAR struct usbhost_class_s *class); - -/* struct block_operations methods */ - -static int usbhost_open(FAR struct inode *inode); -static int usbhost_close(FAR struct inode *inode); -static ssize_t usbhost_read(FAR struct inode *inode, FAR unsigned char *buffer, - size_t startsector, unsigned int nsectors); -#ifdef CONFIG_FS_WRITABLE -static ssize_t usbhost_write(FAR struct inode *inode, - FAR const unsigned char *buffer, size_t startsector, - unsigned int nsectors); -#endif -static int usbhost_geometry(FAR struct inode *inode, - FAR struct geometry *geometry); -static int usbhost_ioctl(FAR struct inode *inode, int cmd, - unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This structure provides the registry entry ID informatino that will be - * used to associate the USB host mass storage class to a connected USB - * device. - */ - -static const const struct usbhost_id_s g_id = -{ - USB_CLASS_MASS_STORAGE, /* base */ - USBMSC_SUBCLASS_SCSI, /* subclass */ - USBMSC_PROTO_BULKONLY, /* proto */ - 0, /* vid */ - 0 /* pid */ -}; - -/* This is the USB host storage class's registry entry */ - -static struct usbhost_registry_s g_storage = -{ - NULL, /* flink */ - usbhost_create, /* create */ - 1, /* nids */ - &g_id /* id[] */ -}; - -/* Block driver operations. This is the interface exposed to NuttX by the - * class that permits it to behave like a block driver. - */ - -static const struct block_operations g_bops = -{ - usbhost_open, /* open */ - usbhost_close, /* close */ - usbhost_read, /* read */ -#ifdef CONFIG_FS_WRITABLE - usbhost_write, /* write */ -#else - NULL, /* write */ -#endif - usbhost_geometry, /* geometry */ - usbhost_ioctl /* ioctl */ -}; - -/* This is an array of pre-allocated USB host storage class instances */ - -#if CONFIG_USBHOST_NPREALLOC > 0 -static struct usbhost_state_s g_prealloc[CONFIG_USBHOST_NPREALLOC]; -#endif - -/* This is a list of free, pre-allocated USB host storage class instances */ - -#if CONFIG_USBHOST_NPREALLOC > 0 -static struct usbhost_state_s *g_freelist; -#endif - -/* This is a bitmap that is used to allocate device names /dev/sda-z. */ - -static uint32_t g_devinuse; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_takesem - * - * Description: - * This is just a wrapper to handle the annoying behavior of semaphore - * waits that return due to the receipt of a signal. - * - ****************************************************************************/ - -static void usbhost_takesem(sem_t *sem) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(sem) != 0) - { - /* The only case that an error should occr here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -/**************************************************************************** - * Name: usbhost_allocclass - * - * Description: - * This is really part of the logic that implements the create() method - * of struct usbhost_registry_s. This function allocates memory for one - * new class instance. - * - * Input Parameters: - * None - * - * Returned Values: - * On success, this function will return a non-NULL instance of struct - * usbhost_class_s. NULL is returned on failure; this function will - * will fail only if there are insufficient resources to create another - * USB host class instance. - * - ****************************************************************************/ - -#if CONFIG_USBHOST_NPREALLOC > 0 -static inline FAR struct usbhost_state_s *usbhost_allocclass(void) -{ - struct usbhost_state_s *priv; - irqstate_t flags; - - /* We may be executing from an interrupt handler so we need to take one of - * our pre-allocated class instances from the free list. - */ - - flags = irqsave(); - priv = g_freelist; - if (priv) - { - g_freelist = priv->class.flink; - priv->class.flink = NULL; - } - irqrestore(flags); - ullvdbg("Allocated: %p\n", priv);; - return priv; -} -#else -static inline FAR struct usbhost_state_s *usbhost_allocclass(void) -{ - FAR struct usbhost_state_s *priv; - - /* We are not executing from an interrupt handler so we can just call - * kmalloc() to get memory for the class instance. - */ - - DEBUGASSERT(!up_interrupt_context()); - priv = (FAR struct usbhost_state_s *)kmalloc(sizeof(struct usbhost_state_s)); - uvdbg("Allocated: %p\n", priv);; - return priv; -} -#endif - -/**************************************************************************** - * Name: usbhost_freeclass - * - * Description: - * Free a class instance previously allocated by usbhost_allocclass(). - * - * Input Parameters: - * class - A reference to the class instance to be freed. - * - * Returned Values: - * None - * - ****************************************************************************/ - -#if CONFIG_USBHOST_NPREALLOC > 0 -static inline void usbhost_freeclass(FAR struct usbhost_state_s *class) -{ - irqstate_t flags; - DEBUGASSERT(class != NULL); - - ullvdbg("Freeing: %p\n", class);; - - /* Just put the pre-allocated class structure back on the freelist */ - - flags = irqsave(); - class->class.flink = g_freelist; - g_freelist = class; - irqrestore(flags); -} -#else -static inline void usbhost_freeclass(FAR struct usbhost_state_s *class) -{ - DEBUGASSERT(class != NULL); - - /* Free the class instance (calling sched_free() in case we are executing - * from an interrupt handler. - */ - - uvdbg("Freeing: %p\n", class);; - kfree(class); -} -#endif - -/**************************************************************************** - * Name: Device name management - * - * Description: - * Some tiny functions to coordinate management of mass storage device names. - * - ****************************************************************************/ - -static int usbhost_allocdevno(FAR struct usbhost_state_s *priv) -{ - irqstate_t flags; - int devno; - - flags = irqsave(); - for (devno = 0; devno < 26; devno++) - { - uint32_t bitno = 1 << devno; - if ((g_devinuse & bitno) == 0) - { - g_devinuse |= bitno; - priv->sdchar = 'a' + devno; - irqrestore(flags); - return OK; - } - } - - irqrestore(flags); - return -EMFILE; -} - -static void usbhost_freedevno(FAR struct usbhost_state_s *priv) -{ - int devno = 'a' - priv->sdchar; - - if (devno >= 0 && devno < 26) - { - irqstate_t flags = irqsave(); - g_devinuse &= ~(1 << devno); - irqrestore(flags); - } -} - -static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname) -{ - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar); -} - -/**************************************************************************** - * Name: CBW/CSW debug helpers - * - * Description: - * The following functions are helper functions used to dump CBWs and CSWs. - * - * Input Parameters: - * cbw/csw - A reference to the CBW/CSW to dump. - * - * Returned Values: - * None - * - ****************************************************************************/ - -#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE) -static void usbhost_dumpcbw(FAR struct usbmsc_cbw_s *cbw) -{ - int i; - - uvdbg("CBW:\n"); - uvdbg(" signature: %08x\n", usbhost_getle32(cbw->signature)); - uvdbg(" tag: %08x\n", usbhost_getle32(cbw->tag)); - uvdbg(" datlen: %08x\n", usbhost_getle32(cbw->datlen)); - uvdbg(" flags: %02x\n", cbw->flags); - uvdbg(" lun: %02x\n", cbw->lun); - uvdbg(" cdblen: %02x\n", cbw->cdblen); - - uvdbg("CDB:\n"); - for (i = 0; i < cbw->cdblen; i += 8) - { - uvdbg(" %02x %02x %02x %02x %02x %02x %02x %02x\n", - cbw->cdb[i], cbw->cdb[i+1], cbw->cdb[i+2], cbw->cdb[i+3], - cbw->cdb[i+4], cbw->cdb[i+5], cbw->cdb[i+6], cbw->cdb[i+7]); - } -} - -static void usbhost_dumpcsw(FAR struct usbmsc_csw_s *csw) -{ - uvdbg("CSW:\n"); - uvdbg(" signature: %08x\n", usbhost_getle32(csw->signature)); - uvdbg(" tag: %08x\n", usbhost_getle32(csw->tag)); - uvdbg(" residue: %08x\n", usbhost_getle32(csw->residue)); - uvdbg(" status: %02x\n", csw->status); -} -#endif - -/**************************************************************************** - * Name: CBW helpers - * - * Description: - * The following functions are helper functions used to format CBWs. - * - * Input Parameters: - * cbw - A reference to allocated and initialized CBW to be built. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline void usbhost_requestsensecbw(FAR struct usbmsc_cbw_s *cbw) -{ - FAR struct scsicmd_requestsense_s *reqsense; - - /* Format the CBW */ - - usbhost_putle32(cbw->datlen, SCSIRESP_FIXEDSENSEDATA_SIZEOF); - cbw->flags = USBMSC_CBWFLAG_IN; - cbw->cdblen = SCSICMD_REQUESTSENSE_SIZEOF; - - /* Format the CDB */ - - reqsense = (FAR struct scsicmd_requestsense_s *)cbw->cdb; - reqsense->opcode = SCSI_CMD_REQUESTSENSE; - reqsense->alloclen = SCSIRESP_FIXEDSENSEDATA_SIZEOF; - - usbhost_dumpcbw(cbw); -} - -static inline void usbhost_testunitreadycbw(FAR struct usbmsc_cbw_s *cbw) -{ - /* Format the CBW */ - - cbw->cdblen = SCSICMD_TESTUNITREADY_SIZEOF; - - /* Format the CDB */ - - cbw->cdb[0] = SCSI_CMD_TESTUNITREADY; - - usbhost_dumpcbw(cbw); -} - -static inline void usbhost_readcapacitycbw(FAR struct usbmsc_cbw_s *cbw) -{ - FAR struct scsicmd_readcapacity10_s *rcap10; - - /* Format the CBW */ - - usbhost_putle32(cbw->datlen, SCSIRESP_READCAPACITY10_SIZEOF); - cbw->flags = USBMSC_CBWFLAG_IN; - cbw->cdblen = SCSICMD_READCAPACITY10_SIZEOF; - - /* Format the CDB */ - - rcap10 = (FAR struct scsicmd_readcapacity10_s *)cbw->cdb; - rcap10->opcode = SCSI_CMD_READCAPACITY10; - - usbhost_dumpcbw(cbw); -} - -static inline void usbhost_inquirycbw (FAR struct usbmsc_cbw_s *cbw) -{ - FAR struct scscicmd_inquiry_s *inq; - - /* Format the CBW */ - - usbhost_putle32(cbw->datlen, SCSIRESP_INQUIRY_SIZEOF); - cbw->flags = USBMSC_CBWFLAG_IN; - cbw->cdblen = SCSICMD_INQUIRY_SIZEOF; - - /* Format the CDB */ - - inq = (FAR struct scscicmd_inquiry_s *)cbw->cdb; - inq->opcode = SCSI_CMD_INQUIRY; - usbhost_putbe16(inq->alloclen, SCSIRESP_INQUIRY_SIZEOF); - - usbhost_dumpcbw(cbw); -} - -static inline void -usbhost_readcbw (size_t startsector, uint16_t blocksize, - unsigned int nsectors, FAR struct usbmsc_cbw_s *cbw) -{ - FAR struct scsicmd_read10_s *rd10; - - /* Format the CBW */ - - usbhost_putle32(cbw->datlen, blocksize * nsectors); - cbw->flags = USBMSC_CBWFLAG_IN; - cbw->cdblen = SCSICMD_READ10_SIZEOF; - - /* Format the CDB */ - - rd10 = (FAR struct scsicmd_read10_s *)cbw->cdb; - rd10->opcode = SCSI_CMD_READ10; - usbhost_putbe32(rd10->lba, startsector); - usbhost_putbe16(rd10->xfrlen, nsectors); - - usbhost_dumpcbw(cbw); -} - -static inline void -usbhost_writecbw(size_t startsector, uint16_t blocksize, - unsigned int nsectors, FAR struct usbmsc_cbw_s *cbw) -{ - FAR struct scsicmd_write10_s *wr10; - - /* Format the CBW */ - - usbhost_putle32(cbw->datlen, blocksize * nsectors); - cbw->cdblen = SCSICMD_WRITE10_SIZEOF; - - /* Format the CDB */ - - wr10 = (FAR struct scsicmd_write10_s *)cbw->cdb; - wr10->opcode = SCSI_CMD_WRITE10; - usbhost_putbe32(wr10->lba, startsector); - usbhost_putbe16(wr10->xfrlen, nsectors); - - usbhost_dumpcbw(cbw); -} - -/**************************************************************************** - * Name: Command helpers - * - * Description: - * The following functions are helper functions used to send commands. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv) -{ - FAR struct usb_ctrlreq_s *req = (FAR struct usb_ctrlreq_s *)priv->tbuffer; - DEBUGASSERT(priv && priv->tbuffer); - int ret; - - /* Request maximum logical unit number. NOTE: On an IN transaction, The - * req and buffer pointers passed to DRVR_CTRLIN may refer to the same - * allocated memory. - */ - - uvdbg("Request maximum logical unit number\n"); - memset(req, 0, sizeof(struct usb_ctrlreq_s)); - req->type = USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE; - req->req = USBMSC_REQ_GETMAXLUN; - usbhost_putle16(req->len, 1); - - ret = DRVR_CTRLIN(priv->drvr, req, priv->tbuffer); - if (ret != OK) - { - /* Devices that do not support multiple LUNs may stall this command. - * On a failure, a single LUN is assumed. - */ - - *(priv->tbuffer) = 0; - } - return OK; -} - -static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv) -{ - FAR struct usbmsc_cbw_s *cbw; - int result; - - /* Initialize a CBW (re-using the allocated transfer buffer) */ - - cbw = usbhost_cbwalloc(priv); - if (!cbw) - { - udbg("ERROR: Failed to create CBW\n"); - return -ENOMEM; - } - - /* Construct and send the CBW */ - - usbhost_testunitreadycbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, - (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) - { - /* Receive the CSW */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) - { - usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); - } - } - - return result; -} - -static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv) -{ - FAR struct usbmsc_cbw_s *cbw; - int result; - - /* Initialize a CBW (re-using the allocated transfer buffer) */ - - cbw = usbhost_cbwalloc(priv); - if (!cbw) - { - udbg("ERROR: Failed to create CBW\n"); - return -ENOMEM; - } - - /* Construct and send the CBW */ - - usbhost_requestsensecbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, - (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) - { - /* Receive the sense data response */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF); - if (result == OK) - { - /* Receive the CSW */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) - { - usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); - } - } - } - - return result; -} - -static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv) -{ - FAR struct usbmsc_cbw_s *cbw; - FAR struct scsiresp_readcapacity10_s *resp; - int result; - - /* Initialize a CBW (re-using the allocated transfer buffer) */ - - cbw = usbhost_cbwalloc(priv); - if (!cbw) - { - udbg("ERROR: Failed to create CBW\n"); - return -ENOMEM; - } - - /* Construct and send the CBW */ - - usbhost_readcapacitycbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, - (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) - { - /* Receive the read capacity CBW IN response */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, SCSIRESP_READCAPACITY10_SIZEOF); - if (result == OK) - { - /* Save the capacity information */ - - resp = (FAR struct scsiresp_readcapacity10_s *)priv->tbuffer; - priv->nblocks = usbhost_getbe32(resp->lba) + 1; - priv->blocksize = usbhost_getbe32(resp->blklen); - - /* Receive the CSW */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) - { - usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); - } - } - } - - return result; -} - -static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv) -{ - FAR struct usbmsc_cbw_s *cbw; - FAR struct scsiresp_inquiry_s *resp; - int result; - - /* Initialize a CBW (re-using the allocated transfer buffer) */ - - cbw = usbhost_cbwalloc(priv); - if (!cbw) - { - udbg("ERROR: Failed to create CBW\n"); - return -ENOMEM; - } - - /* Construct and send the CBW */ - - usbhost_inquirycbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, - (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) - { - /* Receive the CBW IN response */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, SCSIRESP_INQUIRY_SIZEOF); - if (result == OK) - { - /* TODO: If USB debug is enabled, dump the response data here */ - - resp = (FAR struct scsiresp_inquiry_s *)priv->tbuffer; - - /* Receive the CSW */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) - { - usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); - } - } - } - - return result; -} - -/**************************************************************************** - * Name: usbhost_destroy - * - * Description: - * The USB mass storage device has been disconnected and the refernce count - * on the USB host class instance has gone to 1.. Time to destroy the USB - * host class instance. - * - * Input Parameters: - * arg - A reference to the class instance to be destroyed. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_destroy(FAR void *arg) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg; - char devname[DEV_NAMELEN]; - - DEBUGASSERT(priv != NULL); - uvdbg("crefs: %d\n", priv->crefs); - - /* Unregister the block driver */ - - usbhost_mkdevname(priv, devname); - (void)unregister_blockdriver(devname); - - /* Release the device name used by this connection */ - - usbhost_freedevno(priv); - - /* Free the bulk endpoints */ - - if (priv->bulkout) - { - DRVR_EPFREE(priv->drvr, priv->bulkout); - } - - if (priv->bulkin) - { - DRVR_EPFREE(priv->drvr, priv->bulkin); - } - - /* Free any transfer buffers */ - - usbhost_tfree(priv); - - /* Destroy the semaphores */ - - sem_destroy(&priv->exclsem); - - /* Disconnect the USB host device */ - - DRVR_DISCONNECT(priv->drvr); - - /* And free the class instance. Hmmm.. this may execute on the worker - * thread and the work structure is part of what is getting freed. That - * should be okay because once the work contained is removed from the - * queue, it should not longer be accessed by the worker thread. - */ - - usbhost_freeclass(priv); -} - -/**************************************************************************** - * Name: usbhost_cfgdesc - * - * Description: - * This function implements the connect() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to provide the device's configuration - * descriptor to the class so that the class may initialize properly - * - * Input Parameters: - * priv - The USB host class instance. - * configdesc - A pointer to a uint8_t buffer container the configuration descripor. - * desclen - The length in bytes of the configuration descriptor. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * Assumptions: - * This function will *not* be called from an interrupt handler. - * - ****************************************************************************/ - -static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr) -{ - FAR struct usb_cfgdesc_s *cfgdesc; - FAR struct usb_desc_s *desc; - FAR struct usbhost_epdesc_s bindesc; - FAR struct usbhost_epdesc_s boutdesc; - int remaining; - uint8_t found = 0; - int ret; - - DEBUGASSERT(priv != NULL && - configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); - - /* Verify that we were passed a configuration descriptor */ - - cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc; - if (cfgdesc->type != USB_DESC_TYPE_CONFIG) - { - return -EINVAL; - } - - /* Get the total length of the configuration descriptor (little endian). - * It might be a good check to get the number of interfaces here too. - */ - - remaining = (int)usbhost_getle16(cfgdesc->totallen); - - /* Skip to the next entry descriptor */ - - configdesc += cfgdesc->len; - remaining -= cfgdesc->len; - - /* Loop where there are more dscriptors to examine */ - - while (remaining >= sizeof(struct usb_desc_s)) - { - /* What is the next descriptor? */ - - desc = (FAR struct usb_desc_s *)configdesc; - switch (desc->type) - { - /* Interface descriptor. We really should get the number of endpoints - * from this descriptor too. - */ - - case USB_DESC_TYPE_INTERFACE: - { - FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc; - - uvdbg("Interface descriptor\n"); - DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC); - - /* Save the interface number and mark ONLY the interface found */ - - priv->ifno = ifdesc->ifno; - found = USBHOST_IFFOUND; - } - break; - - /* Endpoint descriptor. We expect two bulk endpoints, an IN and an - * OUT. - */ - - case USB_DESC_TYPE_ENDPOINT: - { - FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc; - - uvdbg("Endpoint descriptor\n"); - DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC); - - /* Check for a bulk endpoint. We only support the bulk-only - * protocol so I suppose anything else should really be an error. - */ - - if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_BULK) - { - /* Yes.. it is a bulk endpoint. IN or OUT? */ - - if (USB_ISEPOUT(epdesc->addr)) - { - /* It is an OUT bulk endpoint. There should be only one - * bulk OUT endpoint. - */ - - if ((found & USBHOST_BOUTFOUND) != 0) - { - /* Oops.. more than one endpoint. We don't know - * what to do with this. - */ - - return -EINVAL; - } - found |= USBHOST_BOUTFOUND; - - /* Save the bulk OUT endpoint information */ - - boutdesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; - boutdesc.in = false; - boutdesc.funcaddr = funcaddr; - boutdesc.xfrtype = USB_EP_ATTR_XFER_BULK; - boutdesc.interval = epdesc->interval; - boutdesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); - uvdbg("Bulk OUT EP addr:%d mxpacketsize:%d\n", - boutdesc.addr, boutdesc.mxpacketsize); - } - else - { - /* It is an IN bulk endpoint. There should be only one - * bulk IN endpoint. - */ - - if ((found & USBHOST_BINFOUND) != 0) - { - /* Oops.. more than one endpoint. We don't know - * what to do with this. - */ - - return -EINVAL; - } - found |= USBHOST_BINFOUND; - - /* Save the bulk IN endpoint information */ - - bindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; - bindesc.in = 1; - bindesc.funcaddr = funcaddr; - bindesc.xfrtype = USB_EP_ATTR_XFER_BULK; - bindesc.interval = epdesc->interval; - bindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); - uvdbg("Bulk IN EP addr:%d mxpacketsize:%d\n", - bindesc.addr, bindesc.mxpacketsize); - } - } - } - break; - - /* Other descriptors are just ignored for now */ - - default: - break; - } - - /* If we found everything we need with this interface, then break out - * of the loop early. - */ - - if (found == USBHOST_ALLFOUND) - { - break; - } - - /* Increment the address of the next descriptor */ - - configdesc += desc->len; - remaining -= desc->len; - } - - /* Sanity checking... did we find all of things that we need? Hmmm.. I wonder.. - * can we work read-only or write-only if only one bulk endpoint found? - */ - - if (found != USBHOST_ALLFOUND) - { - ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n", - (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO", - (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO", - (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO"); - return -EINVAL; - } - - /* We are good... Allocate the endpoints */ - - ret = DRVR_EPALLOC(priv->drvr, &boutdesc, &priv->bulkout); - if (ret != OK) - { - udbg("ERROR: Failed to allocate Bulk OUT endpoint\n"); - return ret; - } - - ret = DRVR_EPALLOC(priv->drvr, &bindesc, &priv->bulkin); - if (ret != OK) - { - udbg("ERROR: Failed to allocate Bulk IN endpoint\n"); - (void)DRVR_EPFREE(priv->drvr, priv->bulkout); - return ret; - } - - ullvdbg("Endpoints allocated\n"); - return OK; -} - -/**************************************************************************** - * Name: usbhost_initvolume - * - * Description: - * The USB mass storage device has been successfully connected. This - * completes the initialization operations. It is first called after the - * configuration descriptor has been received. - * - * This function is called from the connect() method. This function always - * executes on the thread of the caller of connect(). - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv) -{ - FAR struct usbmsc_csw_s *csw; - unsigned int retries; - int ret = OK; - - DEBUGASSERT(priv != NULL); - - /* Set aside a transfer buffer for exclusive use by the mass storage driver */ - - ret = usbhost_talloc(priv); - if (ret != OK) - { - udbg("ERROR: Failed to allocate transfer buffer\n"); - return ret; - } - - /* Increment the reference count. This will prevent usbhost_destroy() from - * being called asynchronously if the device is removed. - */ - - priv->crefs++; - DEBUGASSERT(priv->crefs == 2); - - /* Request the maximum logical unit number */ - - uvdbg("Get max LUN\n"); - ret = usbhost_maxlunreq(priv); - - for (retries = 0; retries < USBHOST_MAX_RETRIES /* && ret == OK */; retries++) - { - uvdbg("Test unit ready, retries=%d\n", retries); - - /* Wait just a bit */ - - usleep(50*1000); - - /* Send TESTUNITREADY to see if the unit is ready */ - - ret = usbhost_testunitready(priv); - if (ret == OK) - { - /* Is the unit is ready */ - - csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; - if (csw->status == 0) - { - /* Yes... break out of the loop */ - - break; - } - - /* No.. Request mode sense information. The REQUEST SENSE command - * is sent only "to clear interlocked unit attention conditions." - * The returned status is ignored here. - */ - - uvdbg("Request sense\n"); - ret = usbhost_requestsense(priv); - } - } - - /* Did the unit become ready? Did an error occur? Or did we time out? */ - - if (retries >= USBHOST_MAX_RETRIES) - { - udbg("ERROR: Timeout!\n"); - ret = -ETIMEDOUT; - } - - if (ret == OK) - { - /* Get the capacity of the volume */ - - uvdbg("Read capacity\n"); - ret = usbhost_readcapacity(priv); - if (ret == OK) - { - /* Check the CSW for errors */ - - csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; - if (csw->status != 0) - { - udbg("ERROR: CSW status error: %d\n", csw->status); - ret = -ENODEV; - } - } - } - - /* Get information about the volume */ - - if (ret == OK) - { - /* Inquiry */ - - uvdbg("Inquiry\n"); - ret = usbhost_inquiry(priv); - if (ret == OK) - { - /* Check the CSW for errors */ - - csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; - if (csw->status != 0) - { - udbg("ERROR: CSW status error: %d\n", csw->status); - ret = -ENODEV; - } - } - } - - /* Register the block driver */ - - if (ret == OK) - { - char devname[DEV_NAMELEN]; - - uvdbg("Register block driver\n"); - usbhost_mkdevname(priv, devname); - ret = register_blockdriver(devname, &g_bops, 0, priv); - } - - /* Check if we successfully initialized. We now have to be concerned - * about asynchronous modification of crefs because the block - * driver has been registerd. - */ - - if (ret == OK) - { - usbhost_takesem(&priv->exclsem); - DEBUGASSERT(priv->crefs >= 2); - - /* Decrement the reference count */ - - priv->crefs--; - - /* Handle a corner case where (1) open() has been called so the - * reference count was > 2, but the device has been disconnected. - * In this case, the class instance needs to persist until close() - * is called. - */ - - if (priv->crefs <= 1 && priv->disconnected) - { - /* The will cause the enumeration logic to disconnect - * the class driver. - */ - - ret = -ENODEV; - } - - /* Release the semaphore... there is a race condition here. - * Decrementing the reference count and releasing the semaphore - * allows usbhost_destroy() to execute (on the worker thread); - * the class driver instance could get destoryed before we are - * ready to handle it! - */ - - usbhost_givesem(&priv->exclsem); - } - - return ret; -} - -/**************************************************************************** - * Name: usbhost_getle16 - * - * Description: - * Get a (possibly unaligned) 16-bit little endian value. - * - * Input Parameters: - * val - A pointer to the first byte of the little endian value. - * - * Returned Values: - * A uint16_t representing the whole 16-bit integer value - * - ****************************************************************************/ - -static inline uint16_t usbhost_getle16(const uint8_t *val) -{ - return (uint16_t)val[1] << 8 | (uint16_t)val[0]; -} - -/**************************************************************************** - * Name: usbhost_getbe16 - * - * Description: - * Get a (possibly unaligned) 16-bit big endian value. - * - * Input Parameters: - * val - A pointer to the first byte of the big endian value. - * - * Returned Values: - * A uint16_t representing the whole 16-bit integer value - * - ****************************************************************************/ - -static inline uint16_t usbhost_getbe16(const uint8_t *val) -{ - return (uint16_t)val[0] << 8 | (uint16_t)val[1]; -} - -/**************************************************************************** - * Name: usbhost_putle16 - * - * Description: - * Put a (possibly unaligned) 16-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the little endian value. - * val - The 16-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putle16(uint8_t *dest, uint16_t val) -{ - dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */ - dest[1] = val >> 8; -} - -/**************************************************************************** - * Name: usbhost_putbe16 - * - * Description: - * Put a (possibly unaligned) 16-bit big endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the big endian value. - * val - The 16-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putbe16(uint8_t *dest, uint16_t val) -{ - dest[0] = val >> 8; /* Big endian means MS byte first in byte stream */ - dest[1] = val & 0xff; -} - -/**************************************************************************** - * Name: usbhost_getle32 - * - * Description: - * Get a (possibly unaligned) 32-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the big endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline uint32_t usbhost_getle32(const uint8_t *val) -{ - /* Little endian means LS halfword first in byte stream */ - - return (uint32_t)usbhost_getle16(&val[2]) << 16 | (uint32_t)usbhost_getle16(val); -} - -/**************************************************************************** - * Name: usbhost_getbe32 - * - * Description: - * Get a (possibly unaligned) 32-bit big endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the big endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static inline uint32_t usbhost_getbe32(const uint8_t *val) -{ - /* Big endian means MS halfword first in byte stream */ - - return (uint32_t)usbhost_getbe16(val) << 16 | (uint32_t)usbhost_getbe16(&val[2]); -} - -/**************************************************************************** - * Name: usbhost_putle32 - * - * Description: - * Put a (possibly unaligned) 32-bit little endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the little endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putle32(uint8_t *dest, uint32_t val) -{ - /* Little endian means LS halfword first in byte stream */ - - usbhost_putle16(dest, (uint16_t)(val & 0xffff)); - usbhost_putle16(dest+2, (uint16_t)(val >> 16)); -} - -/**************************************************************************** - * Name: usbhost_putbe32 - * - * Description: - * Put a (possibly unaligned) 32-bit big endian value. - * - * Input Parameters: - * dest - A pointer to the first byte to save the big endian value. - * val - The 32-bit value to be saved. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static void usbhost_putbe32(uint8_t *dest, uint32_t val) -{ - /* Big endian means MS halfword first in byte stream */ - - usbhost_putbe16(dest, (uint16_t)(val >> 16)); - usbhost_putbe16(dest+2, (uint16_t)(val & 0xffff)); -} - -/**************************************************************************** - * Name: usbhost_talloc - * - * Description: - * Allocate transfer buffer memory. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * On sucess, zero (OK) is returned. On failure, an negated errno value - * is returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static inline int usbhost_talloc(FAR struct usbhost_state_s *priv) -{ - DEBUGASSERT(priv && priv->tbuffer == NULL); - return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen); -} - -/**************************************************************************** - * Name: usbhost_tfree - * - * Description: - * Free transfer buffer memory. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * On sucess, zero (OK) is returned. On failure, an negated errno value - * is returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static inline int usbhost_tfree(FAR struct usbhost_state_s *priv) -{ - int result = OK; - DEBUGASSERT(priv); - - if (priv->tbuffer) - { - DEBUGASSERT(priv->drvr); - result = DRVR_FREE(priv->drvr, priv->tbuffer); - priv->tbuffer = NULL; - priv->tbuflen = 0; - } - return result; -} - -/**************************************************************************** - * Name: usbhost_cbwalloc - * - * Description: - * Initialize a CBW (re-using the allocated transfer buffer). Upon - * successful return, the CBW is cleared and has the CBW signature in place. - * - * Input Parameters: - * priv - A reference to the class instance. - * - * Returned Values: - * None - * - ****************************************************************************/ - -static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv) -{ - FAR struct usbmsc_cbw_s *cbw = NULL; - - DEBUGASSERT(priv->tbuffer && priv->tbuflen >= sizeof(struct usbmsc_cbw_s)) - - /* Intialize the CBW sructure */ - - cbw = (FAR struct usbmsc_cbw_s *)priv->tbuffer; - memset(cbw, 0, sizeof(struct usbmsc_cbw_s)); - usbhost_putle32(cbw->signature, USBMSC_CBW_SIGNATURE); - return cbw; -} - -/**************************************************************************** - * struct usbhost_registry_s methods - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_create - * - * Description: - * This function implements the create() method of struct usbhost_registry_s. - * The create() method is a callback into the class implementation. It is - * used to (1) create a new instance of the USB host class state and to (2) - * bind a USB host driver "session" to the class instance. Use of this - * create() method will support environments where there may be multiple - * USB ports and multiple USB devices simultaneously connected. - * - * Input Parameters: - * drvr - An instance of struct usbhost_driver_s that the class - * implementation will "bind" to its state structure and will - * subsequently use to communicate with the USB host driver. - * id - In the case where the device supports multiple base classes, - * subclasses, or protocols, this specifies which to configure for. - * - * Returned Values: - * On success, this function will return a non-NULL instance of struct - * usbhost_class_s that can be used by the USB host driver to communicate - * with the USB host class. NULL is returned on failure; this function - * will fail only if the drvr input parameter is NULL or if there are - * insufficient resources to create another USB host class instance. - * - ****************************************************************************/ - -static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id) -{ - FAR struct usbhost_state_s *priv; - - /* Allocate a USB host mass storage class instance */ - - priv = usbhost_allocclass(); - if (priv) - { - /* Initialize the allocated storage class instance */ - - memset(priv, 0, sizeof(struct usbhost_state_s)); - - /* Assign a device number to this class instance */ - - if (usbhost_allocdevno(priv) == OK) - { - /* Initialize class method function pointers */ - - priv->class.connect = usbhost_connect; - priv->class.disconnected = usbhost_disconnected; - - /* The initial reference count is 1... One reference is held by the driver */ - - priv->crefs = 1; - - /* Initialize semphores (this works okay in the interrupt context) */ - - sem_init(&priv->exclsem, 0, 1); - - /* Bind the driver to the storage class instance */ - - priv->drvr = drvr; - - /* NOTE: We do not yet know the geometry of the USB mass storage device */ - - /* Return the instance of the USB mass storage class */ - - return &priv->class; - } - } - - /* An error occurred. Free the allocation and return NULL on all failures */ - - if (priv) - { - usbhost_freeclass(priv); - } - return NULL; -} - -/**************************************************************************** - * struct usbhost_class_s methods - ****************************************************************************/ -/**************************************************************************** - * Name: usbhost_connect - * - * Description: - * This function implements the connect() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to provide the device's configuration - * descriptor to the class so that the class may initialize properly - * - * Input Parameters: - * class - The USB host class entry previously obtained from a call to create(). - * configdesc - A pointer to a uint8_t buffer container the configuration descripor. - * desclen - The length in bytes of the configuration descriptor. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * NOTE that the class instance remains valid upon return with a failure. It is - * the responsibility of the higher level enumeration logic to call - * CLASS_DISCONNECTED to free up the class driver resources. - * - * Assumptions: - * - This function will *not* be called from an interrupt handler. - * - If this function returns an error, the USB host controller driver - * must call to DISCONNECTED method to recover from the error - * - ****************************************************************************/ - -static int usbhost_connect(FAR struct usbhost_class_s *class, - FAR const uint8_t *configdesc, int desclen, - uint8_t funcaddr) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class; - int ret; - - DEBUGASSERT(priv != NULL && - configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); - - /* Parse the configuration descriptor to get the bulk I/O endpoints */ - - ret = usbhost_cfgdesc(priv, configdesc, desclen, funcaddr); - if (ret != OK) - { - udbg("usbhost_cfgdesc() failed: %d\n", ret); - } - else - { - /* Now configure the LUNs and register the block driver(s) */ - - ret = usbhost_initvolume(priv); - if (ret != OK) - { - udbg("usbhost_initvolume() failed: %d\n", ret); - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbhost_disconnected - * - * Description: - * This function implements the disconnected() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to inform the class that the USB device has - * been disconnected. - * - * Input Parameters: - * class - The USB host class entry previously obtained from a call to - * create(). - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value - * is returned indicating the nature of the failure - * - * Assumptions: - * This function may be called from an interrupt handler. - * - ****************************************************************************/ - -static int usbhost_disconnected(struct usbhost_class_s *class) -{ - FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class; - irqstate_t flags; - - DEBUGASSERT(priv != NULL); - - /* Set an indication to any users of the mass storage device that the device - * is no longer available. - */ - - flags = irqsave(); - priv->disconnected = true; - - /* Now check the number of references on the class instance. If it is one, - * then we can free the class instance now. Otherwise, we will have to - * wait until the holders of the references free them by closing the - * block driver. - */ - - ullvdbg("crefs: %d\n", priv->crefs); - if (priv->crefs == 1) - { - /* Destroy the class instance. If we are executing from an interrupt - * handler, then defer the destruction to the worker thread. - * Otherwise, destroy the instance now. - */ - - if (up_interrupt_context()) - { - /* Destroy the instance on the worker thread. */ - - uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy); - DEBUGASSERT(priv->work.worker == NULL); - (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0); - } - else - { - /* Do the work now */ - - usbhost_destroy(priv); - } - } - - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * struct block_operations methods - ****************************************************************************/ -/**************************************************************************** - * Name: usbhost_open - * - * Description: Open the block device - * - ****************************************************************************/ - -static int usbhost_open(FAR struct inode *inode) -{ - FAR struct usbhost_state_s *priv; - irqstate_t flags; - int ret; - - uvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct usbhost_state_s *)inode->i_private; - - /* Make sure that we have exclusive access to the private data structure */ - - DEBUGASSERT(priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS); - usbhost_takesem(&priv->exclsem); - - /* Check if the mass storage device is still connected. We need to disable - * interrupts momentarily to assure that there are no asynchronous disconnect - * events. - */ - - flags = irqsave(); - if (priv->disconnected) - { - /* No... the block driver is no longer bound to the class. That means that - * the USB storage device is no longer connected. Refuse any further - * attempts to open the driver. - */ - - ret = -ENODEV; - } - else - { - /* Otherwise, just increment the reference count on the driver */ - - priv->crefs++; - ret = OK; - } - irqrestore(flags); - - usbhost_givesem(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: usbhost_close - * - * Description: close the block device - * - ****************************************************************************/ - -static int usbhost_close(FAR struct inode *inode) -{ - FAR struct usbhost_state_s *priv; - irqstate_t flags; - - uvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct usbhost_state_s *)inode->i_private; - - /* Decrement the reference count on the block driver */ - - DEBUGASSERT(priv->crefs > 1); - usbhost_takesem(&priv->exclsem); - priv->crefs--; - - /* Release the semaphore. The following operations when crefs == 1 are - * safe because we know that there is no outstanding open references to - * the block driver. - */ - - usbhost_givesem(&priv->exclsem); - - /* We need to disable interrupts momentarily to assure that there are - * no asynchronous disconnect events. - */ - - flags = irqsave(); - - /* Check if the USB mass storage device is still connected. If the - * storage device is not connected and the reference count just - * decremented to one, then unregister the block driver and free - * the class instance. - */ - - if (priv->crefs <= 1 && priv->disconnected) - { - /* Destroy the class instance */ - - DEBUGASSERT(priv->crefs == 1); - usbhost_destroy(priv); - } - - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Name: usbhost_read - * - * Description: - * Read the specified numer of sectors from the read-ahead buffer or from - * the physical device. - * - ****************************************************************************/ - -static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, - size_t startsector, unsigned int nsectors) -{ - FAR struct usbhost_state_s *priv; - ssize_t ret = 0; - int result; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct usbhost_state_s *)inode->i_private; - uvdbg("startsector: %d nsectors: %d sectorsize: %d\n", - startsector, nsectors, priv->blocksize); - - /* Check if the mass storage device is still connected */ - - if (priv->disconnected) - { - /* No... the block driver is no longer bound to the class. That means that - * the USB storage device is no longer connected. Refuse any attempt to read - * from the device. - */ - - ret = -ENODEV; - } - else if (nsectors > 0) - { - FAR struct usbmsc_cbw_s *cbw; - - usbhost_takesem(&priv->exclsem); - - /* Assume allocation failure */ - - ret = -ENOMEM; - - /* Initialize a CBW (re-using the allocated transfer buffer) */ - - cbw = usbhost_cbwalloc(priv); - if (cbw) - { - /* Loop in the event that EAGAIN is returned (mean that the - * transaction was NAKed and we should try again. - */ - - do - { - /* Assume some device failure */ - - ret = -ENODEV; - - /* Construct and send the CBW */ - - usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, - (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) - { - /* Receive the user data */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - buffer, priv->blocksize * nsectors); - if (result == OK) - { - /* Receive the CSW */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) - { - FAR struct usbmsc_csw_s *csw; - - /* Check the CSW status */ - - csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; - if (csw->status == 0) - { - ret = nsectors; - } - } - } - } - } while (result == -EAGAIN); - } - - usbhost_givesem(&priv->exclsem); - } - - /* On success, return the number of blocks read */ - - return ret; -} - -/**************************************************************************** - * Name: usbhost_write - * - * Description: - * Write the specified number of sectors to the write buffer or to the - * physical device. - * - ****************************************************************************/ - -#ifdef CONFIG_FS_WRITABLE -static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffer, - size_t startsector, unsigned int nsectors) -{ - FAR struct usbhost_state_s *priv; - ssize_t ret; - int result; - - uvdbg("sector: %d nsectors: %d sectorsize: %d\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct usbhost_state_s *)inode->i_private; - - /* Check if the mass storage device is still connected */ - - if (priv->disconnected) - { - /* No... the block driver is no longer bound to the class. That means that - * the USB storage device is no longer connected. Refuse any attempt to - * write to the device. - */ - - ret = -ENODEV; - } - else - { - FAR struct usbmsc_cbw_s *cbw; - - usbhost_takesem(&priv->exclsem); - - /* Assume allocation failure */ - - ret = -ENOMEM; - - /* Initialize a CBW (re-using the allocated transfer buffer) */ - - cbw = usbhost_cbwalloc(priv); - if (cbw) - { - /* Assume some device failure */ - - ret = -ENODEV; - - /* Construct and send the CBW */ - - usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, - (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) - { - /* Send the user data */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, - (uint8_t*)buffer, priv->blocksize * nsectors); - if (result == OK) - { - /* Receive the CSW */ - - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, - priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) - { - FAR struct usbmsc_csw_s *csw; - - /* Check the CSW status */ - - csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; - if (csw->status == 0) - { - ret = nsectors; - } - } - } - } - } - - usbhost_givesem(&priv->exclsem); - } - - /* On success, return the number of blocks written */ - - return ret; -} -#endif - -/**************************************************************************** - * Name: usbhost_geometry - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry) -{ - FAR struct usbhost_state_s *priv; - int ret = -EINVAL; - - uvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - - /* Check if the mass storage device is still connected */ - - priv = (FAR struct usbhost_state_s *)inode->i_private; - if (priv->disconnected) - { - /* No... the block driver is no longer bound to the class. That means that - * the USB storage device is no longer connected. Refuse to return any - * geometry info. - */ - - ret = -ENODEV; - } - else if (geometry) - { - /* Return the geometry of the USB mass storage device */ - - usbhost_takesem(&priv->exclsem); - - geometry->geo_available = true; - geometry->geo_mediachanged = false; -#ifdef CONFIG_FS_WRITABLE - geometry->geo_writeenabled = true; -#else - geometry->geo_writeenabled = false; -#endif - geometry->geo_nsectors = priv->nblocks; - geometry->geo_sectorsize = priv->blocksize; - usbhost_givesem(&priv->exclsem); - - uvdbg("nsectors: %ld sectorsize: %d\n", - (long)geometry->geo_nsectors, geometry->geo_sectorsize); - - ret = OK; - } - - return ret; -} - -/**************************************************************************** - * Name: usbhost_ioctl - * - * Description: Return device geometry - * - ****************************************************************************/ - -static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) -{ - FAR struct usbhost_state_s *priv; - int ret; - - uvdbg("Entry\n"); - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct usbhost_state_s *)inode->i_private; - - /* Check if the mass storage device is still connected */ - - if (priv->disconnected) - { - /* No... the block driver is no longer bound to the class. That means that - * the USB storage device is no longer connected. Refuse to process any - * ioctl commands. - */ - - ret = -ENODEV; - } - else - { - /* Process the IOCTL by command */ - - usbhost_takesem(&priv->exclsem); - switch (cmd) - { - /* Add support for ioctl commands here */ - - default: - ret = -ENOTTY; - break; - } - usbhost_givesem(&priv->exclsem); - } - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usbhost_storageinit - * - * Description: - * Initialize the USB host storage class. This function should be called - * be platform-specific code in order to initialize and register support - * for the USB host storage class. - * - * Input Parameters: - * None - * - * Returned Values: - * On success this function will return zero (OK); A negated errno value - * will be returned on failure. - * - ****************************************************************************/ - -int usbhost_storageinit(void) -{ - /* If we have been configured to use pre-allocated storage class instances, - * then place all of the pre-allocated USB host storage class instances - * into a free list. - */ - -#if CONFIG_USBHOST_NPREALLOC > 0 - int i; - - g_freelist = NULL; - for (i = 0; i < CONFIG_USBHOST_NPREALLOC; i++) - { - struct usbhost_state_s *class = &g_prealloc[i]; - class->class.flink = g_freelist; - g_freelist = class; - } -#endif - - /* Advertise our availability to support (certain) mass storage devices */ - - return usbhost_registerclass(&g_storage); -} - -#endif /* CONFIG_USBHOST && !CONFIG_USBHOST_BULK_DISABLE && !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 */ diff --git a/nuttx/drivers/watchdog.c b/nuttx/drivers/watchdog.c deleted file mode 100644 index 4f7357444..000000000 --- a/nuttx/drivers/watchdog.c +++ /dev/null @@ -1,575 +0,0 @@ -/**************************************************************************** - * drivers/watchdog.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_WATCHDOG - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Debug ********************************************************************/ -/* Non-standard debug that may be enabled just for testing the watchdog driver */ - -#ifdef CONFIG_DEBUG_WATCHDOG -# define wddbg dbg -# define wdvdbg vdbg -# define wdlldbg lldbg -# define wdllvdbg llvdbg -#else -# define wddbg(x...) -# define wdvdbg(x...) -# define wdlldbg(x...) -# define wdllvdbg(x...) -#endif - -/**************************************************************************** - * Private Type Definitions - ****************************************************************************/ - -/* This structure describes the state of the upper half driver */ - -struct watchdog_upperhalf_s -{ - uint8_t crefs; /* The number of times the device has been opened */ - sem_t exclsem; /* Supports mutual exclusion */ - FAR char *path; /* Registration path */ - - /* The contained lower-half driver */ - - FAR struct watchdog_lowerhalf_s *lower; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int wdog_open(FAR struct file *filep); -static int wdog_close(FAR struct file *filep); -static ssize_t wdog_read(FAR struct file *filep, FAR char *buffer, - size_t buflen); -static ssize_t wdog_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen); -static int wdog_ioctl(FAR struct file *filep, int cmd, - unsigned long arg); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations g_wdogops = -{ - wdog_open, /* open */ - wdog_close, /* close */ - wdog_read, /* read */ - wdog_write, /* write */ - 0, /* seek */ - wdog_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/************************************************************************************ - * Name: wdog_open - * - * Description: - * This function is called whenever the watchdog timer device is opened. - * - ************************************************************************************/ - -static int wdog_open(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct watchdog_upperhalf_s *upper = inode->i_private; - uint8_t tmp; - int ret; - - wdvdbg("crefs: %d\n", upper->crefs); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - ret = -errno; - goto errout; - } - - /* Increment the count of references to the device. If this the first - * time that the driver has been opened for this device, then initialize - * the device. - */ - - tmp = upper->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* Save the new open count */ - - upper->crefs = tmp; - ret = OK; - -errout_with_sem: - sem_post(&upper->exclsem); - -errout: - return ret; -} - -/************************************************************************************ - * Name: wdog_close - * - * Description: - * This function is called when the watchdog timer device is closed. - * - ************************************************************************************/ - -static int wdog_close(FAR struct file *filep) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct watchdog_upperhalf_s *upper = inode->i_private; - int ret; - - wdvdbg("crefs: %d\n", upper->crefs); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - ret = -errno; - goto errout; - } - - /* Decrement the references to the driver. If the reference count will - * decrement to 0, then uninitialize the driver. - */ - - if (upper->crefs > 0) - { - upper->crefs--; - } - - sem_post(&upper->exclsem); - ret = OK; - -errout: - return ret; -} - -/************************************************************************************ - * Name: wdog_read - * - * Description: - * A dummy read method. This is provided only to satsify the VFS layer. - * - ************************************************************************************/ - -static ssize_t wdog_read(FAR struct file *filep, FAR char *buffer, size_t buflen) -{ - /* Return zero -- usually meaning end-of-file */ - - return 0; -} - -/************************************************************************************ - * Name: wdog_write - * - * Description: - * A dummy write method. This is provided only to satsify the VFS layer. - * - ************************************************************************************/ - -static ssize_t wdog_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) -{ - return 0; -} - -/************************************************************************************ - * Name: wdog_ioctl - * - * Description: - * The standard ioctl method. This is where ALL of the watchdog timer work is - * done. - * - ************************************************************************************/ - -static int wdog_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct watchdog_upperhalf_s *upper = inode->i_private; - FAR struct watchdog_lowerhalf_s *lower = upper->lower; - int ret; - - wdvdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(upper && lower); - - /* Get exclusive access to the device structures */ - - ret = sem_wait(&upper->exclsem); - if (ret < 0) - { - return ret; - } - - /* Handle built-in ioctl commands */ - - switch (cmd) - { - /* cmd: WDIOC_START - * Description: Start the watchdog timer - * Argument: Ignored - */ - - case WDIOC_START: - { - /* Start the watchdog timer, resetting the time to the current timeout */ - - DEBUGASSERT(lower->ops->start); /* Required */ - ret = lower->ops->start(lower); - } - break; - - /* cmd: WDIOC_STOP - * Description: Stop the watchdog timer - * Argument: Ignored - */ - - case WDIOC_STOP: - { - /* Stop the watchdog timer */ - - DEBUGASSERT(lower->ops->stop); /* Required */ - ret = lower->ops->stop(lower); - } - break; - - /* cmd: WDIOC_GETSTATUS - * Description: et the status of the watchdog timer. - * Argument: A writeable pointer to struct watchdog_status_s. - */ - - case WDIOC_GETSTATUS: - { - FAR struct watchdog_status_s *status; - - /* Get the current watchdog timer status */ - - if (lower->ops->getstatus) /* Optional */ - { - status = (FAR struct watchdog_status_s *)((uintptr_t)arg); - if (status) - { - ret = lower->ops->getstatus(lower, status); - } - else - { - ret = -EINVAL; - } - } - else - { - ret = -ENOSYS; - } - } - break; - - /* cmd: WDIOC_SETTIMEOUT - * Description: Reset the watchdog timeout to this value - * Argument: A 32-bit timeout value in milliseconds. - */ - - case WDIOC_SETTIMEOUT: - { - /* Set a new timeout value (and reset the watchdog timer) */ - - if (lower->ops->settimeout) /* Optional */ - { - ret = lower->ops->settimeout(lower, (uint32_t)arg); - } - else - { - ret = -ENOSYS; - } - } - break; - - /* cmd: WDIOC_CAPTURE - * Description: Do not reset. Instead, called this handler. - * Argument: A pointer to struct watchdog_capture_s. - */ - - case WDIOC_CAPTURE: - { - FAR struct watchdog_capture_s *capture; - - /* Don't reset on watchdog timer timeout; instead, call this user - * provider timeout handler. NOTE: Providing handler==NULL will - * restore the reset behavior. - */ - - if (lower->ops->capture) /* Optional */ - { - capture = (FAR struct watchdog_capture_s *)((uintptr_t)arg); - if (capture) - { - capture->oldhandler = - lower->ops->capture(lower, capture->newhandler); - ret = OK; - } - else - { - ret = -EINVAL; - } - } - else - { - ret = -ENOSYS; - } - } - break; - - /* cmd: WDIOC_KEEPALIVE - * Description: Reset the watchdog timer ("ping", "pet the dog") - * Argument: Argument: Ignored - */ - - case WDIOC_KEEPALIVE: - { - /* Reset the watchdog timer to the current timeout value, prevent any - * imminent watchdog timeouts. This is sometimes referred as - * "pinging" the watchdog timer or "petting the dog". - */ - - if (lower->ops->keepalive) /* Optional */ - { - ret = lower->ops->keepalive(lower); - } - else - { - ret = -ENOSYS; - } - } - break; - - - /* Any unrecognized IOCTL commands might be platform-specific ioctl commands */ - - default: - { - wdvdbg("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg); - - /* An ioctl commands that are not recognized by the "upper-half" - * driver are forwarded to the lower half driver through this - * method. - */ - - if (lower->ops->ioctl) /* Optional */ - { - ret = lower->ops->ioctl(lower, cmd, arg); - } - else - { - ret = -ENOSYS; - } - } - break; - } - - sem_post(&upper->exclsem); - return ret; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: watchdog_register - * - * Description: - * This function binds an instance of a "lower half" watchdog driver with the - * "upper half" watchdog device and registers that device so that can be used - * by application code. - * - * When this function is called, the "lower half" driver should be in the - * disabled state (as if the stop() method had already been called). - * - * Input parameters: - * dev path - The full path to the driver to be registers in the NuttX - * pseudo-filesystem. The recommended convention is to name all watchdog - * drivers as "/dev/watchdog0", "/dev/watchdog1", etc. where the driver - * path differs only in the "minor" number at the end of the device name. - * lower - A pointer to an instance of lower half watchdog driver. This - * instance is bound to the watchdog driver and must persists as long as - * the driver persists. - * - * Returned Value: - * On success, a non-NULL handle is returned to the caller. In the event - * of any failure, a NULL value is returned. - * - ****************************************************************************/ - -FAR void *watchdog_register(FAR const char *path, - FAR struct watchdog_lowerhalf_s *lower) -{ - FAR struct watchdog_upperhalf_s *upper; - int ret; - - DEBUGASSERT(path && lower); - wdvdbg("Entry: path=%s\n", path); - - /* Allocate the upper-half data structure */ - - upper = (FAR struct watchdog_upperhalf_s *) - kzalloc(sizeof(struct watchdog_upperhalf_s)); - if (!upper) - { - wddbg("Upper half allocation failed\n"); - goto errout; - } - - /* Initialize the watchdog timer device structure (it was already zeroed - * by kzalloc()). - */ - - sem_init(&upper->exclsem, 0, 1); - upper->lower = lower; - - /* Copy the registration path */ - - upper->path = strdup(path); - if (!upper->path) - { - wddbg("Path allocation failed\n"); - goto errout_with_upper; - } - - /* Register the watchdog timer device */ - - ret = register_driver(path, &g_wdogops, 0666, upper); - if (ret < 0) - { - wddbg("register_driver failed: %d\n", ret); - goto errout_with_path; - } - - return (FAR void *)upper; - -errout_with_path: - kfree(upper->path); - -errout_with_upper: - sem_destroy(&upper->exclsem); - kfree(upper); - -errout: - return NULL; -} - -/**************************************************************************** - * Name: watchdog_unregister - * - * Description: - * This function can be called to disable and unregister the watchdog - * device driver. - * - * Input parameters: - * handle - This is the handle that was returned by watchdog_register() - * - * Returned Value: - * None - * - ****************************************************************************/ - -void watchdog_unregister(FAR void *handle) -{ - FAR struct watchdog_upperhalf_s *upper; - FAR struct watchdog_lowerhalf_s *lower; - - /* Recover the pointer to the upper-half driver state */ - - upper = (FAR struct watchdog_upperhalf_s *)handle; - lower = upper->lower; - DEBUGASSERT(upper && lower); - - wdvdbg("Unregistering: %s\n", upper->path); - - /* Disable the watchdog timer */ - - DEBUGASSERT(lower->ops->stop); /* Required */ - (void)lower->ops->stop(lower); - - /* Unregister the watchdog timer device */ - - (void)unregister_driver(upper->path); - - /* Then free all of the driver resources */ - - kfree(upper->path); - sem_destroy(&upper->exclsem); - kfree(upper); -} - -#endif /* CONFIG_WATCHDOG */ diff --git a/nuttx/drivers/wireless/Kconfig b/nuttx/drivers/wireless/Kconfig deleted file mode 100644 index ae2bf3130..000000000 --- a/nuttx/drivers/wireless/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# diff --git a/nuttx/drivers/wireless/Make.defs b/nuttx/drivers/wireless/Make.defs deleted file mode 100644 index fa8e8acb5..000000000 --- a/nuttx/drivers/wireless/Make.defs +++ /dev/null @@ -1,47 +0,0 @@ -############################################################################ -# drivers/wireless/Make.defs -# -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -ifeq ($(CONFIG_WIRELESS),y) - -# Include wireless drivers - -CSRCS += cc1101.c ISM1_868MHzGFSK100kbps.c ISM2_905MHzGFSK250kbps.c - -# Include wireless build support - -DEPPATH += --dep-path wireless$(DELIM)cc1101 -VPATH += :wireless$(DELIM)cc1101 -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)wireless$(DELIM)cc1101} -endif diff --git a/nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c b/nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c deleted file mode 100644 index 5c4c58ab2..000000000 --- a/nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** - * drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * Copyright (C) 2011 Ales Verbic. All rights reserved. - * - * Authors: Uros Platise - * Ales Verbic - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#include - -/** Settings for 868 MHz, GFSK at 100kbps - * - * ISM Region 1 (Europe) only, Band 868–870 MHz - * - * Frequency ERP Duty Cycle Bandwidth Remarks - * 868 – 868.6 MHz +14 dBm < 1% No limits - * 868.7 – 869.2 MHz +14 dBm < 0.1% No limits - * 869.3 – 869.4 MHz +10 dBm No limits < 25 kHz Appropriate access protocol required - * 869.4 – 869.65 MHz +27 dBm < 10% < 25 kHz Channels may be combined to one high speed channel - * 869.7 -870 MHz +7 dBm No limits No limits - * - * Deviation = 46.142578 - * Base frequency = 867.999985 - * Carrier frequency = 867.999985 - * Channel number = 0 - * Carrier frequency = 867.999985 - * Modulated = true - * Modulation format = GFSK - * Manchester enable = false - * Sync word qualifier mode = 30/32 sync word bits detected - * Preamble count = 4 - * Channel spacing = 199.813843 - * Carrier frequency = 867.999985 - * Data rate = 99.9069 - * RX filter BW = 210.937500 - * Data format = Normal mode - * Length config = Fixed packet length mode. Length configured in PKTLEN register - * CRC enable = true - * Packet length = 62 - * Device address = 00 - * Address config = NO Address check, no broadcast - * CRC autoflush = true - * PA ramping = false - * TX power = 0 - */ -const struct c1101_rfsettings_s cc1101_rfsettings_ISM1_868MHzGFSK100kbps = { - .FSCTRL1 = 0x08, // FSCTRL1 Frequency Synthesizer Control - .FSCTRL0 = 0x00, // FSCTRL0 Frequency Synthesizer Control - - .FREQ2 = 0x20, // FREQ2 Frequency Control Word, High Byte - .FREQ1 = 0x25, // FREQ1 Frequency Control Word, Middle Byte - .FREQ0 = 0xED, // FREQ0 Frequency Control Word, Low Byte - - .MDMCFG4 = 0x8B, // MDMCFG4 Modem Configuration - .MDMCFG3 = 0xE5, // MDMCFG3 Modem Configuration - .MDMCFG2 = 0x13, // MDMCFG2 Modem Configuration - .MDMCFG1 = 0x22, // MDMCFG1 Modem Configuration - .MDMCFG0 = 0xE5, // MDMCFG0 Modem Configuration - - .DEVIATN = 0x46, // DEVIATN Modem Deviation Setting - - .FOCCFG = 0x1D, // FOCCFG Frequency Offset Compensation Configuration - - .BSCFG = 0x1C, // BSCFG Bit Synchronization Configuration - - .AGCCTRL2= 0xC7, // AGCCTRL2 AGC Control - .AGCCTRL1= 0x00, // AGCCTRL1 AGC Control - .AGCCTRL0= 0xB2, // AGCCTRL0 AGC Control - - .FREND1 = 0xB6, // FREND1 Front End RX Configuration - .FREND0 = 0x10, // FREND0 Front End TX Configuration - - .FSCAL3 = 0xEA, // FSCAL3 Frequency Synthesizer Calibration - .FSCAL2 = 0x2A, // FSCAL2 Frequency Synthesizer Calibration - .FSCAL1 = 0x00, // FSCAL1 Frequency Synthesizer Calibration - .FSCAL0 = 0x1F, // FSCAL0 Frequency Synthesizer Calibration - - .CHMIN = 0, // Fix at 9th channel: 869.80 MHz +- 100 kHz RF Bandwidth - .CHMAX = 9, // single channel - - .PAMAX = 8, // 0 means power OFF, 8 represents PA[7] - .PA = {0x03, 0x0F, 0x1E, 0x27, 0x67, 0x50, 0x81, 0xC2} -}; diff --git a/nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c b/nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c deleted file mode 100644 index e5655bed6..000000000 --- a/nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** - * drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * Copyright (C) 2011 Ales Verbic. All rights reserved. - * - * Authors: Uros Platise - * Ales Verbic - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -#include - -/** Settings for 905 MHz, GFSK at 250kbps - * - * ISM Region 2 (America) only, Band 902–928 MHz - * - * Cordless phones 1 W - * Microwave ovens 750 W - * Industrial heaters 100 kW - * Military radar 1000 kW - * - * Deviation = 126.953125 - * Base frequency = 901.999969 - * Carrier frequency = 905.998993 - * Channel number = 20 - * Carrier frequency = 905.998993 - * Modulated = true - * Modulation format = GFSK - * Manchester enable = false - * Sync word qualifier mode = 30/32 sync word bits detected - * Preamble count = 4 - * Channel spacing = 199.951172 - * Carrier frequency = 905.998993 - * Data rate = 249.939 - * RX filter BW = 541.666667 - * Data format = Normal mode - * Length config = Variable packet length mode. Packet length configured by the first byte after sync word - * CRC enable = true - * Packet length = 61 - * Device address = 0 - * Address config = No address check - * CRC autoflush = false - * PA ramping = false - * TX power = 0 - */ -const struct c1101_rfsettings_s cc1101_rfsettings_ISM2_905MHzGFSK250kbps = { - .FSCTRL1 = 0x0C, // FSCTRL1 Frequency Synthesizer Control - .FSCTRL0 = 0x00, // FSCTRL0 Frequency Synthesizer Control - - .FREQ2 = 0x22, // FREQ2 Frequency Control Word, High Byte - .FREQ1 = 0xB1, // FREQ1 Frequency Control Word, Middle Byte - .FREQ0 = 0x3B, // FREQ0 Frequency Control Word, Low Byte - - .MDMCFG4 = 0x2D, // MDMCFG4 Modem Configuration - .MDMCFG3 = 0x3B, // MDMCFG3 Modem Configuration - .MDMCFG2 = 0x13, // MDMCFG2 Modem Configuration - .MDMCFG1 = 0x22, // MDMCFG1 Modem Configuration - .MDMCFG0 = 0xF8, // MDMCFG0 Modem Configuration - - .DEVIATN = 0x62, // DEVIATN Modem Deviation Setting - - .FOCCFG = 0x1D, // FOCCFG Frequency Offset Compensation Configuration - - .BSCFG = 0x1C, // BSCFG Bit Synchronization Configuration - - .AGCCTRL2= 0xC7, // AGCCTRL2 AGC Control - .AGCCTRL1= 0x00, // AGCCTRL1 AGC Control - .AGCCTRL0= 0xB0, // AGCCTRL0 AGC Control - - .FREND1 = 0xB6, // FREND1 Front End RX Configuration - .FREND0 = 0x10, // FREND0 Front End TX Configuration - - .FSCAL3 = 0xEA, // FSCAL3 Frequency Synthesizer Calibration - .FSCAL2 = 0x2A, // FSCAL2 Frequency Synthesizer Calibration - .FSCAL1 = 0x00, // FSCAL1 Frequency Synthesizer Calibration - .FSCAL0 = 0x1F, // FSCAL0 Frequency Synthesizer Calibration - - .CHMIN = 0, // VERIFY REGULATIONS! - .CHMAX = 0xFF, - - .PAMAX = 8, // 0 means power OFF, 8 represents PA[7] - .PA = {0x03, 0x0E, 0x1E, 0x27, 0x39, 0x8E, 0xCD, 0xC0} -}; diff --git a/nuttx/drivers/wireless/cc1101/Kconfig b/nuttx/drivers/wireless/cc1101/Kconfig deleted file mode 100644 index ae2bf3130..000000000 --- a/nuttx/drivers/wireless/cc1101/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# diff --git a/nuttx/drivers/wireless/cc1101/cc1101.c b/nuttx/drivers/wireless/cc1101/cc1101.c deleted file mode 100644 index 45faaecd2..000000000 --- a/nuttx/drivers/wireless/cc1101/cc1101.c +++ /dev/null @@ -1,812 +0,0 @@ -/**************************************************************************** - * drivers/wireless/cc1101/cc1101.c - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * - * Authors: Uros Platise - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/** \file - * \author Uros Platise - * \brief Chipcon CC1101 Device Driver - * - * Features: - * - Maximum data length: 61 bytes CC1101_PACKET_MAXDATALEN - * - Packet length includes two additional bytes: CC1101_PACKET_MAXTOTALLEN - * - Requires one GDO to trigger end-of-packets in RX and TX modes. - * - Variable packet length with data payload between 1..61 bytes - * (three bytes are reserved for packet length, and RSSI and LQI - * appended at the end of RXFIFO after each reception) - * - Support for General Digital Outputs with overload protection - * (single XOSC pin is allowed, otherwise error is returned) - * - Loadable RF settings, one for ISM Region 1 (Europe) and one for - * ISM Region 2 (Complete America) - * - * Todo: - * - Extend max packet length up to 255 bytes or rather infinite < 4096 bytes - * - Power up/down modes - * - Sequencing between states or add protection for correct termination of - * various different state (so that CC1101 does not block in case of improper use) - * - * \par RSSI and LQI value interpretation - * - * The LQI can be read from the LQI status register or it can be appended - * to the received packet in the RX FIFO. LQI is a metric of the current - * quality of the received signal. The LQI gives an estimate of how easily - * a received signal can be demodulated by accumulating the magnitude of - * the error between ideal constellations and the received signal over - * the 64 symbols immediately following the sync word. LQI is best used - * as a relative measurement of the link quality (a high value indicates - * a better link than what a low value does), since the value is dependent - * on the modulation format. - * - * To simplify: If the received modulation is FSK or GFSK, the receiver - * will measure the frequency of each "bit" and compare it with the - * expected frequency based on the channel frequency and the deviation - * and the measured frequency offset. If other modulations are used, the - * error of the modulated parameter (frequency for FSK/GFSK, phase for - * MSK, amplitude for ASK etc) will be measured against the expected - * ideal value - * - * RSSI (Received Signal Strength Indicator) is a signal strength - * indication. It does not care about the "quality" or "correctness" of - * the signal. LQI does not care about the actual signal strength, but - * the signal quality often is linked to signal strength. This is because - * a strong signal is likely to be less affected by noise and thus will - * be seen as "cleaner" or more "correct" by the receiver. - * - * There are four to five "extreme cases" that can be used to illustrate - * how RSSI and LQI work: - * 1. A weak signal in the presence of noise may give low RSSI and low LQI. - * 2. A weak signal in "total" absence of noise may give low RSSI and high LQI. - * 3. Strong noise (usually coming from an interferer) may give high RSSI and low LQI. - * 4. A strong signal without much noise may give high RSSI and high LQI. - * 5. A very strong signal that causes the receiver to saturate may give - * high RSSI and low LQI. - * - * Note that both RSSI and LQI are best used as relative measurements since - * the values are dependent on the modulation format. - **/ - -#include -#include -#include -#include -#include -#include - -#include -#include - - -/**************************************************************************** - * Declarations - ****************************************************************************/ - -#define CC1101_SPIFREQ_BURST 6500000 /* Hz, no delay */ -#define CC1101_SPIFREQ_SINGLE 9000000 /* Hz, single access only - no delay */ - -#define CC1101_MCSM0_VALUE 0x1C - -/**************************************************************************** - * Chipcon CC1101 Internal Registers - ****************************************************************************/ - -/* Configuration Registers */ - -#define CC1101_IOCFG2 0x00 /* GDO2 output pin configuration */ -#define CC1101_IOCFG1 0x01 /* GDO1 output pin configuration */ -#define CC1101_IOCFG0 0x02 /* GDO0 output pin configuration */ -#define CC1101_FIFOTHR 0x03 /* RX FIFO and TX FIFO thresholds */ -#define CC1101_SYNC1 0x04 /* Sync word, high byte */ -#define CC1101_SYNC0 0x05 /* Sync word, low byte */ -#define CC1101_PKTLEN 0x06 /* Packet length */ -#define CC1101_PKTCTRL1 0x07 /* Packet automation control */ -#define CC1101_PKTCTRL0 0x08 /* Packet automation control */ -#define CC1101_ADDR 0x09 /* Device address */ -#define CC1101_CHANNR 0x0A /* Channel number */ -#define CC1101_FSCTRL1 0x0B /* Frequency synthesizer control */ -#define CC1101_FSCTRL0 0x0C /* Frequency synthesizer control */ -#define CC1101_FREQ2 0x0D /* Frequency control word, high byte */ -#define CC1101_FREQ1 0x0E /* Frequency control word, middle byte */ -#define CC1101_FREQ0 0x0F /* Frequency control word, low byte */ -#define CC1101_MDMCFG4 0x10 /* Modem configuration */ -#define CC1101_MDMCFG3 0x11 /* Modem configuration */ -#define CC1101_MDMCFG2 0x12 /* Modem configuration */ -#define CC1101_MDMCFG1 0x13 /* Modem configuration */ -#define CC1101_MDMCFG0 0x14 /* Modem configuration */ -#define CC1101_DEVIATN 0x15 /* Modem deviation setting */ -#define CC1101_MCSM2 0x16 /* Main Radio Cntrl State Machine config */ -#define CC1101_MCSM1 0x17 /* Main Radio Cntrl State Machine config */ -#define CC1101_MCSM0 0x18 /* Main Radio Cntrl State Machine config */ -#define CC1101_FOCCFG 0x19 /* Frequency Offset Compensation config */ -#define CC1101_BSCFG 0x1A /* Bit Synchronization configuration */ -#define CC1101_AGCCTRL2 0x1B /* AGC control */ -#define CC1101_AGCCTRL1 0x1C /* AGC control */ -#define CC1101_AGCCTRL0 0x1D /* AGC control */ -#define CC1101_WOREVT1 0x1E /* High byte Event 0 timeout */ -#define CC1101_WOREVT0 0x1F /* Low byte Event 0 timeout */ -#define CC1101_WORCTRL 0x20 /* Wake On Radio control */ -#define CC1101_FREND1 0x21 /* Front end RX configuration */ -#define CC1101_FREND0 0x22 /* Front end TX configuration */ -#define CC1101_FSCAL3 0x23 /* Frequency synthesizer calibration */ -#define CC1101_FSCAL2 0x24 /* Frequency synthesizer calibration */ -#define CC1101_FSCAL1 0x25 /* Frequency synthesizer calibration */ -#define CC1101_FSCAL0 0x26 /* Frequency synthesizer calibration */ -#define CC1101_RCCTRL1 0x27 /* RC oscillator configuration */ -#define CC1101_RCCTRL0 0x28 /* RC oscillator configuration */ -#define CC1101_FSTEST 0x29 /* Frequency synthesizer cal control */ -#define CC1101_PTEST 0x2A /* Production test */ -#define CC1101_AGCTEST 0x2B /* AGC test */ -#define CC1101_TEST2 0x2C /* Various test settings */ -#define CC1101_TEST1 0x2D /* Various test settings */ -#define CC1101_TEST0 0x2E /* Various test settings */ - -/* Status registers */ - -#define CC1101_PARTNUM (0x30 | 0xc0) /* Part number */ -#define CC1101_VERSION (0x31 | 0xc0) /* Current version number */ -#define CC1101_FREQEST (0x32 | 0xc0) /* Frequency offset estimate */ -#define CC1101_LQI (0x33 | 0xc0) /* Demodulator estimate for link quality */ -#define CC1101_RSSI (0x34 | 0xc0) /* Received signal strength indication */ -#define CC1101_MARCSTATE (0x35 | 0xc0) /* Control state machine state */ -#define CC1101_WORTIME1 (0x36 | 0xc0) /* High byte of WOR timer */ -#define CC1101_WORTIME0 (0x37 | 0xc0) /* Low byte of WOR timer */ -#define CC1101_PKTSTATUS (0x38 | 0xc0) /* Current GDOx status and packet status */ -#define CC1101_VCO_VC_DAC (0x39 | 0xc0) /* Current setting from PLL cal module */ -#define CC1101_TXBYTES (0x3A | 0xc0) /* Underflow and # of bytes in TXFIFO */ -#define CC1101_RXBYTES (0x3B | 0xc0) /* Overflow and # of bytes in RXFIFO */ -#define CC1101_RCCTRL1_STATUS (0x3C | 0xc0) /* Last RC oscilator calibration results */ -#define CC1101_RCCTRL0_STATUS (0x3D | 0xc0) /* Last RC oscilator calibration results */ - -/* Multi byte memory locations */ - -#define CC1101_PATABLE 0x3E -#define CC1101_TXFIFO 0x3F -#define CC1101_RXFIFO 0x3F - -/* Definitions for burst/single access to registers */ - -#define CC1101_WRITE_BURST 0x40 -#define CC1101_READ_SINGLE 0x80 -#define CC1101_READ_BURST 0xC0 - -/* Strobe commands */ - -#define CC1101_SRES 0x30 /* Reset chip. */ -#define CC1101_SFSTXON 0x31 /* Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). */ -#define CC1101_SXOFF 0x32 /* Turn off crystal oscillator. */ -#define CC1101_SCAL 0x33 /* Calibrate frequency synthesizer and turn it off */ -#define CC1101_SRX 0x34 /* Enable RX. Perform calibration first if switching from IDLE and MCSM0.FS_AUTOCAL=1. */ -#define CC1101_STX 0x35 /* Enable TX. Perform calibration first if IDLE and MCSM0.FS_AUTOCAL=1. */ - /* If switching from RX state and CCA is enabled then go directly to TX if channel is clear. */ -#define CC1101_SIDLE 0x36 /* Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable. */ -#define CC1101_SAFC 0x37 /* Perform AFC adjustment of the frequency synthesizer */ -#define CC1101_SWOR 0x38 /* Start automatic RX polling sequence (Wake-on-Radio) */ -#define CC1101_SPWD 0x39 /* Enter power down mode when CSn goes high. */ -#define CC1101_SFRX 0x3A /* Flush the RX FIFO buffer. */ -#define CC1101_SFTX 0x3B /* Flush the TX FIFO buffer. */ -#define CC1101_SWORRST 0x3C /* Reset real time clock. */ -#define CC1101_SNOP 0x3D /* No operation. */ - -/* Modem Control */ - -#define CC1101_MCSM0_XOSC_FORCE_ON 0x01 - - -/* - * Chip Status Byte - */ - -/* Bit fields in the chip status byte */ - -#define CC1101_STATUS_CHIP_RDYn_BM 0x80 -#define CC1101_STATUS_STATE_BM 0x70 -#define CC1101_STATUS_FIFO_BYTES_AVAILABLE_BM 0x0F - -/* Chip states */ - -#define CC1101_STATE_MASK 0x70 -#define CC1101_STATE_IDLE 0x00 -#define CC1101_STATE_RX 0x10 -#define CC1101_STATE_TX 0x20 -#define CC1101_STATE_FSTXON 0x30 -#define CC1101_STATE_CALIBRATE 0x40 -#define CC1101_STATE_SETTLING 0x50 -#define CC1101_STATE_RX_OVERFLOW 0x60 -#define CC1101_STATE_TX_UNDERFLOW 0x70 - -/* Values of the MACRSTATE register */ - -#define CC1101_MARCSTATE_SLEEP 0x00 -#define CC1101_MARCSTATE_IDLE 0x01 -#define CC1101_MARCSTATE_XOFF 0x02 -#define CC1101_MARCSTATE_VCOON_MC 0x03 -#define CC1101_MARCSTATE_REGON_MC 0x04 -#define CC1101_MARCSTATE_MANCAL 0x05 -#define CC1101_MARCSTATE_VCOON 0x06 -#define CC1101_MARCSTATE_REGON 0x07 -#define CC1101_MARCSTATE_STARTCAL 0x08 -#define CC1101_MARCSTATE_BWBOOST 0x09 -#define CC1101_MARCSTATE_FS_LOCK 0x0A -#define CC1101_MARCSTATE_IFADCON 0x0B -#define CC1101_MARCSTATE_ENDCAL 0x0C -#define CC1101_MARCSTATE_RX 0x0D -#define CC1101_MARCSTATE_RX_END 0x0E -#define CC1101_MARCSTATE_RX_RST 0x0F -#define CC1101_MARCSTATE_TXRX_SWITCH 0x10 -#define CC1101_MARCSTATE_RXFIFO_OVERFLOW 0x11 -#define CC1101_MARCSTATE_FSTXON 0x12 -#define CC1101_MARCSTATE_TX 0x13 -#define CC1101_MARCSTATE_TX_END 0x14 -#define CC1101_MARCSTATE_RXTX_SWITCH 0x15 -#define CC1101_MARCSTATE_TXFIFO_UNDERFLOW 0x16 - -/* Part number and version */ - -#define CC1101_PARTNUM_VALUE 0x00 -#define CC1101_VERSION_VALUE 0x04 - -/* - * Others ... - */ - -#define CC1101_LQI_CRC_OK_BM 0x80 -#define CC1101_LQI_EST_BM 0x7F - - -/**************************************************************************** - * Private Data Types - ****************************************************************************/ - -#define FLAGS_RXONLY 1 /* Indicates receive operation only */ -#define FLAGS_XOSCENABLED 2 /* Indicates that one pin is configured as XOSC/n */ - -struct cc1101_dev_s { - const struct c1101_rfsettings_s *rfsettings; - - struct spi_dev_s * spi; - uint8_t isrpin; /* CC1101 pin used to trigger interrupts */ - uint32_t pinset; /* GPIO of the MCU */ - uint8_t flags; - uint8_t channel; - uint8_t power; -}; - - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -void cc1101_access_begin(struct cc1101_dev_s * dev) -{ - (void)SPI_LOCK(dev->spi, true); - SPI_SELECT(dev->spi, SPIDEV_WIRELESS, true); - SPI_SETMODE(dev->spi, SPIDEV_MODE0); /* CPOL=0, CPHA=0 */ - SPI_SETBITS(dev->spi, 8); -} - - -void cc1101_access_end(struct cc1101_dev_s * dev) -{ - SPI_SELECT(dev->spi, SPIDEV_WIRELESS, false); - (void)SPI_LOCK(dev->spi, false); -} - - -/** CC1101 Access with Range Check - * - * \param dev CC1101 Private Structure - * \param addr CC1101 Address - * \param buf Pointer to buffer, either for read or write access - * \param length when >0 it denotes read access, when <0 it denotes write - * access of -length. abs(length) greater of 1 implies burst mode, - * however - * \return OK on success or errno is set. - */ -int cc1101_access(struct cc1101_dev_s * dev, uint8_t addr, uint8_t *buf, int length) -{ - int stabyte; - - /* Address cannot explicitly define READ command while length WRITE. - * Also access to these cells is only permitted as one byte, eventhough - * transfer is marked as BURST! - */ - - if ( (addr & CC1101_READ_SINGLE) && length != 1 ) - return ERROR; - - /* Prepare SPI */ - - cc1101_access_begin(dev); - - if (length>1 || length < -1) - SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_BURST); - else SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_SINGLE); - - /* Transfer */ - - if (length <= 0) { /* 0 length are command strobes */ - if (length < -1) - addr |= CC1101_WRITE_BURST; - - stabyte = SPI_SEND(dev->spi, addr); - if (length) { - SPI_SNDBLOCK(dev->spi, buf, -length); - } - } - else { - addr |= CC1101_READ_SINGLE; - if (length > 1) - addr |= CC1101_READ_BURST; - - stabyte = SPI_SEND(dev->spi, addr); - SPI_RECVBLOCK(dev->spi, buf, length); - } - - cc1101_access_end(dev); - - return stabyte; -} - - -/** Strobes command and returns chip status byte - * - * By default commands are send as Write. To a command, - * CC1101_READ_SINGLE may be OR'ed to obtain the number of RX bytes - * pending in RX FIFO. - */ -inline uint8_t cc1101_strobe(struct cc1101_dev_s * dev, uint8_t command) -{ - uint8_t status; - - cc1101_access_begin(dev); - SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_SINGLE); - - status = SPI_SEND(dev->spi, command); - - cc1101_access_end(dev); - - return status; -} - - -int cc1101_reset(struct cc1101_dev_s * dev) -{ - cc1101_strobe(dev, CC1101_SRES); - return OK; -} - - -int cc1101_checkpart(struct cc1101_dev_s * dev) -{ - uint8_t partnum, version; - - if (cc1101_access(dev, CC1101_PARTNUM, &partnum, 1) < 0 || - cc1101_access(dev, CC1101_VERSION, &version, 1) < 0) - return ERROR; - - if (partnum == CC1101_PARTNUM_VALUE && version == CC1101_VERSION_VALUE) - return OK; - - return ERROR; -} - - -void cc1101_dumpregs(struct cc1101_dev_s * dev, uint8_t addr, uint8_t length) -{ - uint8_t buf[0x30], i; - - cc1101_access(dev, addr, buf, length); - - printf("CC1101[%2x]: ", addr); - for (i=0; i RX, RX -> RX: 0x3F */ - values[2] = CC1101_MCSM0_VALUE; /* Calibrate on IDLE -> RX/TX, OSC Timeout = ~500 us - TODO: has XOSC_FORCE_ON */ - cc1101_access(dev, CC1101_MCSM2, values, -3); - - /* Wake-On Radio Control */ - - // Not used yet. - - // WOREVT1:WOREVT0 - 16-bit timeout register -} - - -/**************************************************************************** - * Callbacks - ****************************************************************************/ - -volatile int cc1101_interrupt = 0; - -/** External line triggers this callback - * - * The concept todo is: - * - GPIO provides EXTI Interrupt - * - It should handle EXTI Interrupts in ISR, to which chipcon can - * register a callback (and others). The ISR then foreach() calls a - * its callback, and it is up to peripheral to find, whether the cause - * of EXTI ISR was itself. - **/ - -int cc1101_eventcb(int irq, FAR void *context) -{ - cc1101_interrupt++; - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -struct cc1101_dev_s * cc1101_init(struct spi_dev_s * spi, uint8_t isrpin, - uint32_t pinset, const struct c1101_rfsettings_s * rfsettings) -{ - struct cc1101_dev_s * dev; - - ASSERT(spi); - - if ( (dev = kmalloc( sizeof(struct cc1101_dev_s) )) == NULL) { - errno = ENOMEM; - return NULL; - } - - dev->rfsettings = rfsettings; - dev->spi = spi; - dev->isrpin = isrpin; - dev->pinset = pinset; - dev->flags = 0; - dev->channel = rfsettings->CHMIN; - dev->power = rfsettings->PAMAX; - - /* Reset chip, check status bytes */ - - if ( cc1101_reset(dev) < 0 ) { - kfree(dev); - errno = EFAULT; - return NULL; - } - - /* Check part compatibility */ - - if ( cc1101_checkpart(dev) < 0 ) { - kfree(dev); - errno = ENODEV; - return NULL; - } - - /* Configure CC1101: - * - disable GDOx for best performance - * - load RF - * - and packet control - */ - - cc1101_setgdo(dev, CC1101_PIN_GDO0, CC1101_GDO_HIZ); - cc1101_setgdo(dev, CC1101_PIN_GDO1, CC1101_GDO_HIZ); - cc1101_setgdo(dev, CC1101_PIN_GDO2, CC1101_GDO_HIZ); - cc1101_setrf(dev, rfsettings); - cc1101_setpacketctrl(dev); - - /* Set the ISR to be triggerred on falling edge of the: - * - * 6 (0x06) Asserts when sync word has been sent / received, and - * de-asserts at the end of the packet. In RX, the pin will de-assert - * when the optional address check fails or the RX FIFO overflows. - * In TX the pin will de-assert if the TX FIFO underflows. - */ - - cc1101_setgdo(dev, dev->isrpin, CC1101_GDO_SYNC); - - /* Bind to external interrupt line */ - - // depends on STM32: TODO: Make that config within pinset and - // provide general gpio interface - //stm32_gpiosetevent(pinset, false, true, true, cc1101_eventcb); - - return dev; -} - - -int cc1101_deinit(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - - /* Release interrupt */ - //stm32_gpiosetevent(pinset, false, false, false, NULL); - - /* Power down chip */ - cc1101_powerdown(dev); - - /* Release external interrupt line */ - kfree(dev); - - return 0; -} - - -int cc1101_powerup(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - return 0; -} - - -int cc1101_powerdown(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - return 0; -} - - -int cc1101_setgdo(struct cc1101_dev_s * dev, uint8_t pin, uint8_t function) -{ - ASSERT(dev); - ASSERT(pin <= CC1101_IOCFG0); - - if (function >= CC1101_GDO_CLK_XOSC1) { - - /* Only one pin can be enabled at a time as XOSC/n */ - - if (dev->flags & FLAGS_XOSCENABLED) return -EPERM; - - /* Force XOSC to stay active even in sleep mode */ - - int value = CC1101_MCSM0_VALUE | CC1101_MCSM0_XOSC_FORCE_ON; - cc1101_access(dev, CC1101_MCSM0, &value, -1); - - dev->flags |= FLAGS_XOSCENABLED; - } - else if (dev->flags & FLAGS_XOSCENABLED) { - - /* Disable XOSC in sleep mode */ - - int value = CC1101_MCSM0_VALUE; - cc1101_access(dev, CC1101_MCSM0, &value, -1); - - dev->flags &= ~FLAGS_XOSCENABLED; - } - - return cc1101_access(dev, pin, &function, -1); -} - - -int cc1101_setrf(struct cc1101_dev_s * dev, const struct c1101_rfsettings_s *settings) -{ - ASSERT(dev); - ASSERT(settings); - - if (cc1101_access(dev, CC1101_FSCTRL1, &settings->FSCTRL1, -11) < 0) return ERROR; - if (cc1101_access(dev, CC1101_FOCCFG, &settings->FOCCFG, -5) < 0) return ERROR; - if (cc1101_access(dev, CC1101_FREND1, &settings->FREND1, -6) < 0) return ERROR; - - /* Load Power Table */ - - if (cc1101_access(dev, CC1101_PATABLE, settings->PA, -8) < 0) return ERROR; - - /* If channel is out of valid range, mark that. Limit power. - * We are not allowed to send any data, but are allowed to listen - * and receive. - */ - - cc1101_setchannel(dev, dev->channel); - cc1101_setpower(dev, dev->power); - - return OK; -} - - -int cc1101_setchannel(struct cc1101_dev_s * dev, uint8_t channel) -{ - ASSERT(dev); - - /* Store localy in further checks */ - - dev->channel = channel; - - /* If channel is out of valid, we are allowed to listen and receive only */ - - if (channel < dev->rfsettings->CHMIN || channel > dev->rfsettings->CHMAX) - dev->flags |= FLAGS_RXONLY; - else dev->flags &= ~FLAGS_RXONLY; - - cc1101_access(dev, CC1101_CHANNR, &dev->channel, -1); - - return dev->flags & FLAGS_RXONLY; -} - - -uint8_t cc1101_setpower(struct cc1101_dev_s * dev, uint8_t power) -{ - ASSERT(dev); - - if (power > dev->rfsettings->PAMAX) - power = dev->rfsettings->PAMAX; - - dev->power = power; - - if (power == 0) { - dev->flags |= FLAGS_RXONLY; - return 0; - } - else dev->flags &= ~FLAGS_RXONLY; - - /* Add remaining part from RF table (to get rid of readback) */ - - power--; - power |= dev->rfsettings->FREND0; - - /* On error, report that as zero power */ - - if (cc1101_access(dev, CC1101_FREND0, &power, -1) < 0) - dev->power = 0; - - return dev->power; -} - - -int cc1101_calcRSSIdBm(int rssi) -{ - if (rssi >= 128) rssi -= 256; - return (rssi >> 1) - 74; -} - - -int cc1101_receive(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - - /* \todo Wait for IDLE before going into another state? */ - - cc1101_interrupt = 0; - - cc1101_strobe(dev, CC1101_SRX | CC1101_READ_SINGLE); - - return 0; -} - - -int cc1101_read(struct cc1101_dev_s * dev, uint8_t * buf, size_t size) -{ - ASSERT(dev); - - if (buf==NULL) { - if (size==0) return 64; - // else received packet size - return 0; - } - - if (cc1101_interrupt == 0) return 0; - - int status = cc1101_strobe(dev, CC1101_SNOP | CC1101_READ_SINGLE); - - if (status & CC1101_STATUS_FIFO_BYTES_AVAILABLE_BM && - (status & CC1101_STATE_MASK) == CC1101_STATE_IDLE) { - - uint8_t nbytes; - - cc1101_access(dev, CC1101_RXFIFO, &nbytes, 1); - - nbytes += 2; /* RSSI and LQI */ - - cc1101_access(dev, CC1101_RXFIFO, buf, (nbytes > size) ? size : nbytes); - - /* Flush remaining bytes, if there is no room to receive - * or if there is a BAD CRC - */ - - if (nbytes > size || (nbytes <= size && !(buf[nbytes-1]&0x80)) ) { - printf("Flushing RX FIFO\n"); - cc1101_strobe(dev, CC1101_SFRX); - } - - return nbytes; - } - - return 0; -} - - -int cc1101_write(struct cc1101_dev_s * dev, const uint8_t * buf, size_t size) -{ - uint8_t packetlen; - - ASSERT(dev); - ASSERT(buf); - - if (dev->flags & FLAGS_RXONLY) return -EPERM; - - /* Present limit */ - if (size > CC1101_PACKET_MAXDATALEN) - packetlen = CC1101_PACKET_MAXDATALEN; - else packetlen = size; - - cc1101_access(dev, CC1101_TXFIFO, &packetlen, -1); - cc1101_access(dev, CC1101_TXFIFO, buf, -size); - - return 0; -} - - -int cc1101_send(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - - if (dev->flags & FLAGS_RXONLY) return -EPERM; - - cc1101_interrupt = 0; - - cc1101_strobe(dev, CC1101_STX); - - /* wait until send, going to IDLE */ - - while( cc1101_interrupt == 0 ); - - return 0; -} - - -int cc1101_idle(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - cc1101_strobe(dev, CC1101_SIDLE); - return 0; -} -- cgit v1.2.3