diff options
38 files changed, 4925 insertions, 0 deletions
diff --git a/package/fonera-mp3-drv/Makefile b/package/fonera-mp3-drv/Makefile new file mode 100644 index 000000000..81fbaddb9 --- /dev/null +++ b/package/fonera-mp3-drv/Makefile @@ -0,0 +1,44 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# $Id: Makefile 6501 2007-03-04 04:41:46Z pavlov $ + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=fonera-mp3-driver +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/fonera-mp3-driver + SUBMENU:=Other modules + VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(BOARD)-$(LINUX_RELEASE) + DEPENDS:=@LINUX_2_6_ATHEROS + TITLE:=Fonera-MP3 driver (VS1011X) + DESCRIPTION:=driver for a vs1011X attached to a fonera + FILES:=$(PKG_BUILD_DIR)/mp3_drv.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,25,mp3-drv) +endef + +define Build/Prepare + $(call Build/Prepare/Default) + $(CP) -r src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + ARCH="$(LINUX_KARCH)" V="$(V)" \ + SUBDIRS="$(PKG_BUILD_DIR)" \ + KERNELVERSION="$(KERNEL)" \ + KERNEL_SOURCES="$(LINUX_DIR)" \ + KDIR="$(LINUX_DIR)" +endef + +$(eval $(call KernelPackage,fonera-mp3-driver)) diff --git a/package/fonera-mp3-drv/src/Makefile b/package/fonera-mp3-drv/src/Makefile new file mode 100644 index 000000000..fda632ead --- /dev/null +++ b/package/fonera-mp3-drv/src/Makefile @@ -0,0 +1,19 @@ +# $Id$ +# +# Makefile for mp3 - vs1011b driver +# +# Copyright (C) 2007 John '2B|!2B' Crispin john@phrozen.org +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version +# 2 of the License, or (at your option) any later version. +# + +obj-m := mp3_drv.o + +ifeq ($(MAKING_MODULES),1) +#export-objs := mp3_drv.o + +-include $(TOPDIR)/Rules.make +endif diff --git a/package/fonera-mp3-drv/src/ar531x.h b/package/fonera-mp3-drv/src/ar531x.h new file mode 100644 index 000000000..9176c15ab --- /dev/null +++ b/package/fonera-mp3-drv/src/ar531x.h @@ -0,0 +1,1124 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +#ifndef AR531X_H +#define AR531X_H 1 + + +#ifndef CONFIG_AR531X_COBRA + +#include <asm/addrspace.h> + +/* Address Map */ +#define AR531X_WLAN0 0x18000000 +#define AR531X_WLAN1 0x18500000 +#define AR531X_ENET0 0x18100000 +#define AR531X_ENET1 0x18200000 +#define AR531X_SDRAMCTL 0x18300000 +#define AR531X_FLASHCTL 0x18400000 +#define AR531X_APBBASE 0x1c000000 +#define AR531X_FLASH 0x1e000000 + +/* + * AR531X_NUM_ENET_MAC defines the number of ethernet MACs that + * should be considered available. The AR5312 supports 2 enet MACS, + * even though many reference boards only actually use 1 of them + * (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch. + * The AR2312 supports 1 enet MAC. + */ +#define AR531X_NUM_ENET_MAC 2 + +/* + * Need these defines to determine true number of ethernet MACs + */ +#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */ +#define AR531X_RADIO_MASK_OFF 0xc8 +#define AR531X_RADIO0_MASK 0x0003 +#define AR531X_RADIO1_MASK 0x000c +#define AR531X_RADIO1_S 2 + +/* + * AR531X_NUM_WMAC defines the number of Wireless MACs that\ + * should be considered available. + */ +#define AR531X_NUM_WMAC 2 + +/* Reset/Timer Block Address Map */ +#define AR531X_RESETTMR (AR531X_APBBASE + 0x3000) +#define AR531X_TIMER (AR531X_RESETTMR + 0x0000) /* countdown timer */ +#define AR531X_WD_CTRL (AR531X_RESETTMR + 0x0008) /* watchdog cntrl */ +#define AR531X_WD_TIMER (AR531X_RESETTMR + 0x000c) /* watchdog timer */ +#define AR531X_ISR (AR531X_RESETTMR + 0x0010) /* Intr Status Reg */ +#define AR531X_IMR (AR531X_RESETTMR + 0x0014) /* Intr Mask Reg */ +#define AR531X_RESET (AR531X_RESETTMR + 0x0020) +#define AR5312_CLOCKCTL1 (AR531X_RESETTMR + 0x0064) +#define AR5312_SCRATCH (AR531X_RESETTMR + 0x006c) +#define AR531X_PROCADDR (AR531X_RESETTMR + 0x0070) +#define AR531X_PROC1 (AR531X_RESETTMR + 0x0074) +#define AR531X_DMAADDR (AR531X_RESETTMR + 0x0078) +#define AR531X_DMA1 (AR531X_RESETTMR + 0x007c) +#define AR531X_ENABLE (AR531X_RESETTMR + 0x0080) /* interface enb */ +#define AR531X_REV (AR531X_RESETTMR + 0x0090) /* revision */ + +/* AR531X_WD_CTRL register bit field definitions */ +#define AR531X_WD_CTRL_IGNORE_EXPIRATION 0x0000 +#define AR531X_WD_CTRL_NMI 0x0001 +#define AR531X_WD_CTRL_RESET 0x0002 + +/* AR531X_ISR register bit field definitions */ +#define AR531X_ISR_NONE 0x0000 +#define AR531X_ISR_TIMER 0x0001 +#define AR531X_ISR_AHBPROC 0x0002 +#define AR531X_ISR_AHBDMA 0x0004 +#define AR531X_ISR_GPIO 0x0008 +#define AR531X_ISR_UART0 0x0010 +#define AR531X_ISR_UART0DMA 0x0020 +#define AR531X_ISR_WD 0x0040 +#define AR531X_ISR_LOCAL 0x0080 + +/* AR531X_RESET register bit field definitions */ +#define AR531X_RESET_SYSTEM 0x00000001 /* cold reset full system */ +#define AR531X_RESET_PROC 0x00000002 /* cold reset MIPS core */ +#define AR531X_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */ +#define AR531X_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ +#define AR531X_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ +#define AR531X_RESET_ENET0 0x00000020 /* cold reset ENET0 mac */ +#define AR531X_RESET_ENET1 0x00000040 /* cold reset ENET1 mac */ +#define AR531X_RESET_UART0 0x00000100 /* cold reset UART0 (high speed) */ +#define AR531X_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */ +#define AR531X_RESET_APB 0x00000400 /* cold reset APB (ar5312) */ +#define AR531X_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */ +#define AR531X_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */ +#define AR531X_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BaseBand */ +#define AR531X_RESET_NMI 0x00010000 /* send an NMI to the processor */ +#define AR531X_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 mac */ +#define AR531X_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 baseband */ +#define AR531X_RESET_LOCAL_BUS 0x00080000 /* reset local bus */ +#define AR531X_RESET_WDOG 0x00100000 /* last reset was a watchdog */ + +#define AR531X_RESET_WMAC0_BITS \ + AR531X_RESET_WLAN0 |\ + AR531X_RESET_WARM_WLAN0_MAC |\ + AR531X_RESET_WARM_WLAN0_BB + +#define AR531X_RESERT_WMAC1_BITS \ + AR531X_RESET_WLAN1 |\ + AR531X_RESET_WARM_WLAN1_MAC |\ + AR531X_RESET_WARM_WLAN1_BB + +/* AR5312_CLOCKCTL1 register bit field definitions */ +#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 +#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 +#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 +#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 +#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 + +/* Valid for AR5312 and AR2312 */ +#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 +#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 +#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 +#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 +#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 + +/* Valid for AR2313 */ +#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000 +#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12 +#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000 +#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16 +#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000 + + +/* AR531X_ENABLE register bit field definitions */ +#define AR531X_ENABLE_WLAN0 0x0001 +#define AR531X_ENABLE_ENET0 0x0002 +#define AR531X_ENABLE_ENET1 0x0004 +#define AR531X_ENABLE_UART_AND_WLAN1_PIO 0x0008 /* UART, and WLAN1 PIOs */ +#define AR531X_ENABLE_WLAN1_DMA 0x0010 /* WLAN1 DMAs */ +#define AR531X_ENABLE_WLAN1 \ + (AR531X_ENABLE_UART_AND_WLAN1_PIO | AR531X_ENABLE_WLAN1_DMA) + +/* AR531X_REV register bit field definitions */ +#define AR531X_REV_WMAC_MAJ 0xf000 +#define AR531X_REV_WMAC_MAJ_S 12 +#define AR531X_REV_WMAC_MIN 0x0f00 +#define AR531X_REV_WMAC_MIN_S 8 +#define AR531X_REV_MAJ 0x00f0 +#define AR531X_REV_MAJ_S 4 +#define AR531X_REV_MIN 0x000f +#define AR531X_REV_MIN_S 0 +#define AR531X_REV_CHIP (REV_MAJ|REV_MIN) + +/* Major revision numbers, bits 7..4 of Revision ID register */ +#define AR531X_REV_MAJ_AR5312 0x4 +#define AR531X_REV_MAJ_AR2313 0x5 + +/* Minor revision numbers, bits 3..0 of Revision ID register */ +#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */ +#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */ + +/* AR531X_FLASHCTL register bit field definitions */ +#define FLASHCTL_IDCY 0x0000000f /* Idle cycle turn around time */ +#define FLASHCTL_IDCY_S 0 +#define FLASHCTL_WST1 0x000003e0 /* Wait state 1 */ +#define FLASHCTL_WST1_S 5 +#define FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */ +#define FLASHCTL_WST2 0x0000f800 /* Wait state 2 */ +#define FLASHCTL_WST2_S 11 +#define FLASHCTL_AC 0x00070000 /* Flash address check (added) */ +#define FLASHCTL_AC_S 16 +#define FLASHCTL_AC_128K 0x00000000 +#define FLASHCTL_AC_256K 0x00010000 +#define FLASHCTL_AC_512K 0x00020000 +#define FLASHCTL_AC_1M 0x00030000 +#define FLASHCTL_AC_2M 0x00040000 +#define FLASHCTL_AC_4M 0x00050000 +#define FLASHCTL_AC_8M 0x00060000 +#define FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */ +#define FLASHCTL_E 0x00080000 /* Flash bank enable (added) */ +#define FLASHCTL_BUSERR 0x01000000 /* Bus transfer error status flag */ +#define FLASHCTL_WPERR 0x02000000 /* Write protect error status flag */ +#define FLASHCTL_WP 0x04000000 /* Write protect */ +#define FLASHCTL_BM 0x08000000 /* Burst mode */ +#define FLASHCTL_MW 0x30000000 /* Memory width */ +#define FLASHCTL_MWx8 0x00000000 /* Memory width x8 */ +#define FLASHCTL_MWx16 0x10000000 /* Memory width x16 */ +#define FLASHCTL_MWx32 0x20000000 /* Memory width x32 (not supported) */ +#define FLASHCTL_ATNR 0x00000000 /* Access type == no retry */ +#define FLASHCTL_ATR 0x80000000 /* Access type == retry every */ +#define FLASHCTL_ATR4 0xc0000000 /* Access type == retry every 4 */ + +/* ARM Flash Controller -- 3 flash banks with either x8 or x16 devices. */ +#define AR531X_FLASHCTL0 (AR531X_FLASHCTL + 0x00) +#define AR531X_FLASHCTL1 (AR531X_FLASHCTL + 0x04) +#define AR531X_FLASHCTL2 (AR531X_FLASHCTL + 0x08) + +/* ARM SDRAM Controller -- just enough to determine memory size */ +#define AR531X_MEM_CFG1 (AR531X_SDRAMCTL + 0x04) +#define MEM_CFG1_AC0 0x00000700 /* bank 0: SDRAM addr check (added) */ +#define MEM_CFG1_AC0_S 8 +#define MEM_CFG1_AC1 0x00007000 /* bank 1: SDRAM addr check (added) */ +#define MEM_CFG1_AC1_S 12 + +/* GPIO Address Map */ +#define AR531X_GPIO (AR531X_APBBASE + 0x2000) +#define AR531X_GPIO_DO (AR531X_GPIO + 0x00) /* output register */ +#define AR531X_GPIO_DI (AR531X_GPIO + 0x04) /* intput register */ +#define AR531X_GPIO_CR (AR531X_GPIO + 0x08) /* control register */ + +/* GPIO Control Register bit field definitions */ +#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ +#define GPIO_CR_O(x) (0 << (x)) /* mask for output */ +#define GPIO_CR_I(x) (1 << (x)) /* mask for input */ +#define GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */ +#define GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */ + + +typedef unsigned int AR531X_REG; + +#define sysRegRead(phys) \ + (*(volatile AR531X_REG *)PHYS_TO_K1(phys)) + +#define sysRegWrite(phys, val) \ + ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val)) + + +/* + * This is board-specific data that is stored in a "fixed" location in flash. + * It is shared across operating systems, so it should not be changed lightly. + * The main reason we need it is in order to extract the ethernet MAC + * address(es). + */ +struct ar531x_boarddata { + u32 magic; /* board data is valid */ +#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */ + u16 cksum; /* checksum (starting with BD_REV 2) */ + u16 rev; /* revision of this struct */ +#define BD_REV 4 + char boardName[64]; /* Name of board */ + u16 major; /* Board major number */ + u16 minor; /* Board minor number */ + u32 config; /* Board configuration */ +#define BD_ENET0 0x00000001 /* ENET0 is stuffed */ +#define BD_ENET1 0x00000002 /* ENET1 is stuffed */ +#define BD_UART1 0x00000004 /* UART1 is stuffed */ +#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */ +#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */ +#define BD_SYSLED 0x00000020 /* System LED stuffed */ +#define BD_EXTUARTCLK 0x00000040 /* External UART clock */ +#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */ +#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */ +#define BD_WLAN0 0x00000200 /* Enable WLAN0 */ +#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */ +#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */ +#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */ +#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */ +#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */ +#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */ +#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */ +#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */ + u16 resetConfigGpio; /* Reset factory GPIO pin */ + u16 sysLedGpio; /* System LED GPIO pin */ + + u32 cpuFreq; /* CPU core frequency in Hz */ + u32 sysFreq; /* System frequency in Hz */ + u32 cntFreq; /* Calculated C0_COUNT frequency */ + + u8 wlan0Mac[6]; + u8 enet0Mac[6]; + u8 enet1Mac[6]; + + u16 pciId; /* Pseudo PCIID for common code */ + u16 memCap; /* cap bank1 in MB */ + + /* version 3 */ + u8 wlan1Mac[6]; /* (ar5212) */ +}; + +#else + +/* + * Add support for Cobra + * + * AR531XPLUSreg.h Register definitions for Atheros AR5311 and AR5312 chipsets. + * - WLAN registers are listed in + * hal/ar5211/ar5211Reg.h + * hal/ar5212/ar5212Reg.h + * - Ethernet registers are listed in ar531xenet.h + * - Standard UART is 16550 compatible. + */ + + +/* + * Address map + */ +#define AR531XPLUS_SDRAM0 0x00000000 /* DRAM */ +#define AR531XPLUS_SPI_READ 0x08000000 /* SPI FLASH */ +#define AR531XPLUS_WLAN0 0xB0000000 /* Wireless MMR */ +#define AR531XPLUS_PCI 0xB0100000 /* PCI MMR */ +#define AR531XPLUS_SDRAMCTL 0xB0300000 /* SDRAM MMR */ +#define AR531XPLUS_LOCAL 0xB0400000 /* LOCAL BUS MMR */ +#define AR531XPLUS_ENET0 0xB0500000 /* ETHERNET MMR */ +#define AR531XPLUS_DSLBASE 0xB1000000 /* RESET CONTROL MMR */ +#define AR531XPLUS_UART0 0xB1100003 /* UART MMR */ +#define AR531XPLUS_SPI 0xB1300000 /* SPI FLASH MMR */ +#define AR531XPLUS_FLASHBT 0xBfc00000 /* ro boot alias to FLASH */ +#define AR531XPLUS_RAM1 0x40000000 /* ram alias */ +#define AR531XPLUS_PCIEXT 0x80000000 /* pci external */ +#define AR531XPLUS_RAM2 0xc0000000 /* ram alias */ +#define AR531XPLUS_RAM3 0xe0000000 /* ram alias */ + +#define AR531X_ENET0 AR531XPLUS_ENET0 +#define AR531X_ENET1 0 +/* + * Reset Register + */ +#define AR531XPLUS_COLD_RESET (AR531XPLUS_DSLBASE + 0x0000) + +/* Cold Reset */ +#define RESET_COLD_AHB 0x00000001 +#define RESET_COLD_APB 0x00000002 +#define RESET_COLD_CPU 0x00000004 +#define RESET_COLD_CPUWARM 0x00000008 +#define RESET_SYSTEM (RESET_COLD_CPU | RESET_COLD_APB | RESET_COLD_AHB) /* full system */ + +/* Warm Reset */ + +#define AR531XPLUS_RESET (AR531XPLUS_DSLBASE + 0x0004) +#define AR531X_RESET AR531XPLUS_RESET + +#define RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */ +#define RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BaseBand */ +#define RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */ +#define RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */ +#define RESET_MEMCTL 0x00000010 /* warm reset memory controller */ +#define RESET_LOCAL 0x00000020 /* warm reset local bus */ +#define RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */ +#define RESET_SPI 0x00000080 /* warm reset SPI interface */ +#define RESET_UART0 0x00000100 /* warm reset UART0 */ +#define RESET_IR_RSVD 0x00000200 /* warm reset IR interface */ +#define RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */ +#define RESET_ENET0 0x00000800 /* cold reset ENET0 mac */ + +#define AR531X_RESET_ENET0 RESET_ENET0 +#define AR531X_RESET_EPHY0 RESET_EPHY0 +#define AR531X_RESET_ENET1 0 +#define AR531X_RESET_EPHY1 0 + +/* + * AHB master arbitration control + */ +#define AR531XPLUS_AHB_ARB_CTL (AR531XPLUS_DSLBASE + 0x0008) + +#define ARB_CPU 0x00000001 /* CPU, default */ +#define ARB_WLAN 0x00000002 /* WLAN */ +#define ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */ +#define ARB_LOCAL 0x00000008 /* LOCAL */ +#define ARB_PCI 0x00000010 /* PCI */ +#define ARB_ETHERNET 0x00000020 /* Ethernet */ +#define ARB_RETRY 0x00000100 /* retry policy, debug only */ + +/* + * Config Register + */ +#define AR531XPLUS_ENDIAN_CTL (AR531XPLUS_DSLBASE + 0x000c) + +#define CONFIG_AHB 0x00000001 /* EC - AHB bridge endianess */ +#define CONFIG_WLAN 0x00000002 /* WLAN byteswap */ +#define CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */ +#define CONFIG_PCI 0x00000008 /* PCI byteswap */ +#define CONFIG_MEMCTL 0x00000010 /* Memory controller endianess */ +#define CONFIG_LOCAL 0x00000020 /* Local bus byteswap */ +#define CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */ + +#define CONFIG_MERGE 0x00000200 /* CPU write buffer merge */ +#define CONFIG_CPU 0x00000400 /* CPU big endian */ +#define CONFIG_PCIAHB 0x00000800 +#define CONFIG_PCIAHB_BRIDGE 0x00001000 +#define CONFIG_SPI 0x00008000 /* SPI byteswap */ +#define CONFIG_CPU_DRAM 0x00010000 +#define CONFIG_CPU_PCI 0x00020000 +#define CONFIG_CPU_MMR 0x00040000 +#define CONFIG_BIG 0x00000400 + + +/* + * NMI control + */ +#define AR531XPLUS_NMI_CTL (AR531XPLUS_DSLBASE + 0x0010) + +#define NMI_EN 1 + +/* + * Revision Register - Initial value is 0x3010 (WMAC 3.0, AR531X 1.0). + */ +#define AR531XPLUS_SREV (AR531XPLUS_DSLBASE + 0x0014) + +#define AR531X_REV AR531XPLUS_SREV + +#define REV_MAJ 0x00f0 +#define REV_MAJ_S 4 +#define REV_MIN 0x000f +#define REV_MIN_S 0 +#define REV_CHIP (REV_MAJ|REV_MIN) + +#define AR531X_REV_MAJ REV_MAJ +#define AR531X_REV_MAJ_S REV_MAJ_S +#define AR531X_REV_MIN REV_MIN +#define AR531X_REV_MIN_S REV_MIN_S +#define REV_CHIP (REV_MAJ|REV_MIN) +/* + * Need these defines to determine true number of ethernet MACs + */ +#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */ +#define AR531X_RADIO_MASK_OFF 0xc8 +#define AR531X_RADIO0_MASK 0x0003 +#define AR531X_RADIO1_MASK 0x000c +#define AR531X_RADIO1_S 2 + +/* Major revision numbers, bits 7..4 of Revision ID register */ +#define AR531X_REV_MAJ_AR5312 0x4 +#define AR531X_REV_MAJ_AR2313 0x5 + +/* + * AR531X_NUM_ENET_MAC defines the number of ethernet MACs that + * should be considered available. The AR5312 supports 2 enet MACS, + * even though many reference boards only actually use 1 of them + * (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch. + * The AR2312 supports 1 enet MAC. + */ +#define AR531X_NUM_ENET_MAC 1 + +/* + * Interface Enable + */ +#define AR531XPLUS_IF_CTL (AR531XPLUS_DSLBASE + 0x0018) + +#define IF_MASK 0x00000007 +#define IF_DISABLED 0 +#define IF_PCI 1 +#define IF_TS_LOCAL 2 +#define IF_ALL 3 /* only for emulation with separate pins */ +#define IF_LOCAL_HOST 0x00000008 +#define IF_PCI_HOST 0x00000010 +#define IF_PCI_INTR 0x00000020 +#define IF_PCI_CLK_MASK 0x00030000 +#define IF_PCI_CLK_INPUT 0 +#define IF_PCI_CLK_OUTPUT_LOW 1 +#define IF_PCI_CLK_OUTPUT_CLK 2 +#define IF_PCI_CLK_OUTPUT_HIGH 3 +#define IF_PCI_CLK_SHIFT 16 + + +/* Major revision numbers, bits 7..4 of Revision ID register */ +#define REV_MAJ_AR5311 0x01 +#define REV_MAJ_AR5312 0x04 +#define REV_MAJ_AR5315 0x0B + +/* + * APB Interrupt control + */ + +#define AR531XPLUS_ISR (AR531XPLUS_DSLBASE + 0x0020) +#define AR531XPLUS_IMR (AR531XPLUS_DSLBASE + 0x0024) +#define AR531XPLUS_GISR (AR531XPLUS_DSLBASE + 0x0028) + +#define ISR_UART0 0x0001 /* high speed UART */ +#define ISR_I2C_RSVD 0x0002 /* I2C bus */ +#define ISR_SPI 0x0004 /* SPI bus */ +#define ISR_AHB 0x0008 /* AHB error */ +#define ISR_APB 0x0010 /* APB error */ +#define ISR_TIMER 0x0020 /* timer */ +#define ISR_GPIO 0x0040 /* GPIO */ +#define ISR_WD 0x0080 /* watchdog */ +#define ISR_IR_RSVD 0x0100 /* IR */ + +#define IMR_UART0 ISR_UART0 +#define IMR_I2C_RSVD ISR_I2C_RSVD +#define IMR_SPI ISR_SPI +#define IMR_AHB ISR_AHB +#define IMR_APB ISR_APB +#define IMR_TIMER ISR_TIMER +#define IMR_GPIO ISR_GPIO +#define IMR_WD ISR_WD +#define IMR_IR_RSVD ISR_IR_RSVD + +#define GISR_MISC 0x0001 +#define GISR_WLAN0 0x0002 +#define GISR_MPEGTS_RSVD 0x0004 +#define GISR_LOCALPCI 0x0008 +#define GISR_WMACPOLL 0x0010 +#define GISR_TIMER 0x0020 +#define GISR_ETHERNET 0x0040 + +/* + * Interrupt routing from IO to the processor IP bits + * Define our inter mask and level + */ +#define AR531XPLUS_INTR_MISCIO SR_IBIT3 +#define AR531XPLUS_INTR_WLAN0 SR_IBIT4 +#define AR531XPLUS_INTR_ENET0 SR_IBIT5 +#define AR531XPLUS_INTR_LOCALPCI SR_IBIT6 +#define AR531XPLUS_INTR_WMACPOLL SR_IBIT7 +#define AR531XPLUS_INTR_COMPARE SR_IBIT8 + +/* + * Timers + */ +#define AR531XPLUS_TIMER (AR531XPLUS_DSLBASE + 0x0030) +#define AR531XPLUS_RELOAD (AR531XPLUS_DSLBASE + 0x0034) +#define AR531XPLUS_WD (AR531XPLUS_DSLBASE + 0x0038) +#define AR531XPLUS_WDC (AR531XPLUS_DSLBASE + 0x003c) + +#define WDC_RESET 0x00000002 /* reset on watchdog */ +#define WDC_NMI 0x00000001 /* NMI on watchdog */ +#define WDC_IGNORE_EXPIRATION 0x00000000 + +/* + * Interface Debug + */ +#define AR531X_FLASHDBG (AR531X_RESETTMR + 0x0040) +#define AR531X_MIIDBG (AR531X_RESETTMR + 0x0044) + + +/* + * CPU Performance Counters + */ +#define AR531XPLUS_PERFCNT0 (AR531XPLUS_DSLBASE + 0x0048) +#define AR531XPLUS_PERFCNT1 (AR531XPLUS_DSLBASE + 0x004c) + +#define PERF_DATAHIT 0x0001 /* Count Data Cache Hits */ +#define PERF_DATAMISS 0x0002 /* Count Data Cache Misses */ +#define PERF_INSTHIT 0x0004 /* Count Instruction Cache Hits */ +#define PERF_INSTMISS 0x0008 /* Count Instruction Cache Misses */ +#define PERF_ACTIVE 0x0010 /* Count Active Processor Cycles */ +#define PERF_WBHIT 0x0020 /* Count CPU Write Buffer Hits */ +#define PERF_WBMISS 0x0040 /* Count CPU Write Buffer Misses */ + +#define PERF_EB_ARDY 0x0001 /* Count EB_ARdy signal */ +#define PERF_EB_AVALID 0x0002 /* Count EB_AValid signal */ +#define PERF_EB_WDRDY 0x0004 /* Count EB_WDRdy signal */ +#define PERF_EB_RDVAL 0x0008 /* Count EB_RdVal signal */ +#define PERF_VRADDR 0x0010 /* Count valid read address cycles */ +#define PERF_VWADDR 0x0020 /* Count valid write address cycles */ +#define PERF_VWDATA 0x0040 /* Count valid write data cycles */ + +/* + * AHB Error Reporting. + */ +#define AR531XPLUS_AHB_ERR0 (AR531XPLUS_DSLBASE + 0x0050) /* error */ +#define AR531XPLUS_AHB_ERR1 (AR531XPLUS_DSLBASE + 0x0054) /* haddr */ +#define AR531XPLUS_AHB_ERR2 (AR531XPLUS_DSLBASE + 0x0058) /* hwdata */ +#define AR531XPLUS_AHB_ERR3 (AR531XPLUS_DSLBASE + 0x005c) /* hrdata */ +#define AR531XPLUS_AHB_ERR4 (AR531XPLUS_DSLBASE + 0x0060) /* status */ + +#define AHB_ERROR_DET 1 /* AHB Error has been detected, */ + /* write 1 to clear all bits in ERR0 */ +#define AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */ +#define AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */ + +#define PROCERR_HMAST 0x0000000f +#define PROCERR_HMAST_DFLT 0 +#define PROCERR_HMAST_WMAC 1 +#define PROCERR_HMAST_ENET 2 +#define PROCERR_HMAST_PCIENDPT 3 +#define PROCERR_HMAST_LOCAL 4 +#define PROCERR_HMAST_CPU 5 +#define PROCERR_HMAST_PCITGT 6 + +#define PROCERR_HMAST_S 0 +#define PROCERR_HWRITE 0x00000010 +#define PROCERR_HSIZE 0x00000060 +#define PROCERR_HSIZE_S 5 +#define PROCERR_HTRANS 0x00000180 +#define PROCERR_HTRANS_S 7 +#define PROCERR_HBURST 0x00000e00 +#define PROCERR_HBURST_S 9 + + + +/* + * Clock Control + */ +#define AR531XPLUS_PLLC_CTL (AR531XPLUS_DSLBASE + 0x0064) +#define AR531XPLUS_PLLV_CTL (AR531XPLUS_DSLBASE + 0x0068) +#define AR531XPLUS_CPUCLK (AR531XPLUS_DSLBASE + 0x006c) +#define AR531XPLUS_AMBACLK (AR531XPLUS_DSLBASE + 0x0070) +#define AR531XPLUS_SYNCCLK (AR531XPLUS_DSLBASE + 0x0074) +#define AR531XPLUS_DSL_SLEEP_CTL (AR531XPLUS_DSLBASE + 0x0080) +#define AR531XPLUS_DSL_SLEEP_DUR (AR531XPLUS_DSLBASE + 0x0084) + +/* PLLc Control fields */ +#define PLLC_REF_DIV_M 0x00000003 +#define PLLC_REF_DIV_S 0 +#define PLLC_FDBACK_DIV_M 0x0000007C +#define PLLC_FDBACK_DIV_S 2 +#define PLLC_ADD_FDBACK_DIV_M 0x00000080 +#define PLLC_ADD_FDBACK_DIV_S 7 +#define PLLC_CLKC_DIV_M 0x0001c000 +#define PLLC_CLKC_DIV_S 14 +#define PLLC_CLKM_DIV_M 0x00700000 +#define PLLC_CLKM_DIV_S 20 + +/* CPU CLK Control fields */ +#define CPUCLK_CLK_SEL_M 0x00000003 +#define CPUCLK_CLK_SEL_S 0 +#define CPUCLK_CLK_DIV_M 0x0000000c +#define CPUCLK_CLK_DIV_S 2 + +/* AMBA CLK Control fields */ +#define AMBACLK_CLK_SEL_M 0x00000003 +#define AMBACLK_CLK_SEL_S 0 +#define AMBACLK_CLK_DIV_M 0x0000000c +#define AMBACLK_CLK_DIV_S 2 + +#if defined(COBRA_EMUL) +#define AR531XPLUS_AMBA_CLOCK_RATE 20000000 +#define AR531XPLUS_CPU_CLOCK_RATE 40000000 +#else +#if defined(DEFAULT_PLL) +#define AR531XPLUS_AMBA_CLOCK_RATE 40000000 +#define AR531XPLUS_CPU_CLOCK_RATE 40000000 +#else +#define AR531XPLUS_AMBA_CLOCK_RATE 92000000 +#define AR531XPLUS_CPU_CLOCK_RATE 184000000 +#endif /* ! DEFAULT_PLL */ +#endif /* ! COBRA_EMUL */ + +#define AR531XPLUS_UART_CLOCK_RATE AR531XPLUS_AMBA_CLOCK_RATE +#define AR531XPLUS_SDRAM_CLOCK_RATE AR531XPLUS_AMBA_CLOCK_RATE + +/* + * The UART computes baud rate as: + * baud = clock / (16 * divisor) + * where divisor is specified as a High Byte (DLM) and a Low Byte (DLL). + */ +#define DESIRED_BAUD_RATE 38400 + +/* + * The WATCHDOG value is computed as + * 10 seconds * AR531X_WATCHDOG_CLOCK_RATE + */ +#define DESIRED_WATCHDOG_SECONDS 10 +#define AR531X_WATCHDOG_TIME \ + (DESIRED_WATCHDOG_SECONDS * AR531X_WATCHDOG_CLOCK_RATE) + + +#define CLOCKCTL_UART0 0x0010 /* enable UART0 external clock */ + + + /* + * Applicable "PCICFG" bits for WLAN(s). Assoc status and LED mode. + */ +#define AR531X_PCICFG (AR531X_RESETTMR + 0x00b0) +#define ASSOC_STATUS_M 0x00000003 +#define ASSOC_STATUS_NONE 0 +#define ASSOC_STATUS_PENDING 1 +#define ASSOC_STATUS_ASSOCIATED 2 +#define LED_MODE_M 0x0000001c +#define LED_BLINK_THRESHOLD_M 0x000000e0 +#define LED_SLOW_BLINK_MODE 0x00000100 + +/* + * GPIO + */ + +#define AR531XPLUS_GPIO_DI (AR531XPLUS_DSLBASE + 0x0088) +#define AR531XPLUS_GPIO_DO (AR531XPLUS_DSLBASE + 0x0090) +#define AR531XPLUS_GPIO_CR (AR531XPLUS_DSLBASE + 0x0098) +#define AR531XPLUS_GPIO_INT (AR531XPLUS_DSLBASE + 0x00a0) + +#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ +#define GPIO_CR_O(x) (1 << (x)) /* output */ +#define GPIO_CR_I(x) (0 << (x)) /* input */ + +#define GPIO_INT(x,Y) ((x) << (8 * (Y))) /* interrupt enable */ +#define GPIO_INT_M(Y) ((0x3F) << (8 * (Y))) /* mask for int */ +#define GPIO_INT_LVL(x,Y) ((x) << (8 * (Y) + 6)) /* interrupt level */ +#define GPIO_INT_LVL_M(Y) ((0x3) << (8 * (Y) + 6)) /* mask for int level */ + +#define AR531XPLUS_RESET_GPIO 5 +#define AR531XPLUS_NUM_GPIO 22 + + +/* + * PCI Clock Control + */ + +#define AR531XPLUS_PCICLK (AR531XPLUS_DSLBASE + 0x00a4) + +#define PCICLK_INPUT_M 0x3 +#define PCICLK_INPUT_S 0 + +#define PCICLK_PLLC_CLKM 0 +#define PCICLK_PLLC_CLKM1 1 +#define PCICLK_PLLC_CLKC 2 +#define PCICLK_REF_CLK 3 + +#define PCICLK_DIV_M 0xc +#define PCICLK_DIV_S 2 + +#define PCICLK_IN_FREQ 0 +#define PCICLK_IN_FREQ_DIV_6 1 +#define PCICLK_IN_FREQ_DIV_8 2 +#define PCICLK_IN_FREQ_DIV_10 3 + +/* + * Observation Control Register + */ +#define AR531XPLUS_OCR (AR531XPLUS_DSLBASE + 0x00b0) +#define OCR_GPIO0_IRIN 0x0040 +#define OCR_GPIO1_IROUT 0x0080 +#define OCR_GPIO3_RXCLR 0x0200 + +/* + * General Clock Control + */ + +#define AR531XPLUS_MISCCLK (AR531XPLUS_DSLBASE + 0x00b4) +#define MISCCLK_PLLBYPASS_EN 0x00000001 +#define MISCCLK_PROCREFCLK 0x00000002 + +/* + * SDRAM Controller + * - No read or write buffers are included. + */ +#define AR531XPLUS_MEM_CFG (AR531XPLUS_SDRAMCTL + 0x00) +#define AR531XPLUS_MEM_CTRL (AR531XPLUS_SDRAMCTL + 0x0c) +#define AR531XPLUS_MEM_REF (AR531XPLUS_SDRAMCTL + 0x10) + +#define SDRAM_DATA_WIDTH_M 0x00006000 +#define SDRAM_DATA_WIDTH_S 13 + +#define SDRAM_COL_WIDTH_M 0x00001E00 +#define SDRAM_COL_WIDTH_S 9 + +#define SDRAM_ROW_WIDTH_M 0x000001E0 +#define SDRAM_ROW_WIDTH_S 5 + +#define SDRAM_BANKADDR_BITS_M 0x00000018 +#define SDRAM_BANKADDR_BITS_S 3 + + +/* + * SDRAM Memory Refresh (MEM_REF) value is computed as: + * MEMCTL_SREFR = (Tr * hclk_freq) / R + * where Tr is max. time of refresh of any single row + * R is number of rows in the DRAM + * For most 133MHz SDRAM parts, Tr=64ms, R=4096 or 8192 + */ +#if defined(COBRA_EMUL) +#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x96 +#else +#if defined(DEFAULT_PLL) +#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x200 +#else +#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x61a +#endif /* ! DEFAULT_PLL */ +#endif + +#if defined(AR531XPLUS) + +#define AR531XPLUS_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */ +#define AR531XPLUS_SDRAM_DATA_WIDTH 16 /* bits */ +#define AR531XPLUS_SDRAM_COL_WIDTH 8 +#define AR531XPLUS_SDRAM_ROW_WIDTH 12 + +#else + +#define AR531XPLUS_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */ +#define AR531XPLUS_SDRAM_DATA_WIDTH 16 +#define AR531XPLUS_SDRAM_COL_WIDTH 8 +#define AR531XPLUS_SDRAM_ROW_WIDTH 12 + +#endif /* ! AR531XPLUS */ + +/* + * SPI Flash Interface Registers + */ + +#define AR531XPLUS_SPI_CTL (AR531XPLUS_SPI + 0x00) +#define AR531XPLUS_SPI_OPCODE (AR531XPLUS_SPI + 0x04) +#define AR531XPLUS_SPI_DATA (AR531XPLUS_SPI + 0x08) + +#define SPI_CTL_START 0x00000100 +#define SPI_CTL_BUSY 0x00010000 +#define SPI_CTL_TXCNT_MASK 0x0000000f +#define SPI_CTL_RXCNT_MASK 0x000000f0 +#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff +#define SPI_CTL_SIZE_MASK 0x00060000 + +#define SPI_CTL_CLK_SEL_MASK 0x03000000 +#define SPI_OPCODE_MASK 0x000000ff + +/* + * PCI-MAC Configuration registers + */ +#define PCI_MAC_RC (AR531XPLUS_PCI + 0x4000) +#define PCI_MAC_SCR (AR531XPLUS_PCI + 0x4004) +#define PCI_MAC_INTPEND (AR531XPLUS_PCI + 0x4008) +#define PCI_MAC_SFR (AR531XPLUS_PCI + 0x400C) +#define PCI_MAC_PCICFG (AR531XPLUS_PCI + 0x4010) +#define PCI_MAC_SREV (AR531XPLUS_PCI + 0x4020) + +#define PCI_MAC_RC_MAC 0x00000001 +#define PCI_MAC_RC_BB 0x00000002 + +#define PCI_MAC_SCR_SLMODE_M 0x00030000 +#define PCI_MAC_SCR_SLMODE_S 16 +#define PCI_MAC_SCR_SLM_FWAKE 0 +#define PCI_MAC_SCR_SLM_FSLEEP 1 +#define PCI_MAC_SCR_SLM_NORMAL 2 + +#define PCI_MAC_SFR_SLEEP 0x00000001 + +#define PCI_MAC_PCICFG_SPWR_DN 0x00010000 + + + + +/* + * PCI Bus Interface Registers + */ +#define AR531XPLUS_PCI_1MS_REG (AR531XPLUS_PCI + 0x0008) +#define AR531XPLUS_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ + +#define AR531XPLUS_PCI_MISC_CONFIG (AR531XPLUS_PCI + 0x000c) +#define AR531XPLUS_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR531XPLUS_PCIMISC_CFG_SEL 0x00000002 /* mem or config cycles */ +#define AR531XPLUS_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */ +#define AR531XPLUS_PCIMISC_RST_MODE 0x00000030 +#define AR531XPLUS_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */ +#define AR531XPLUS_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */ +#define AR531XPLUS_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */ +#define AR531XPLUS_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */ +#define AR531XPLUS_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */ +#define AR531XPLUS_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */ +#define AR531XPLUS_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */ +#define AR531XPLUS_PCICACHE_DIS 0x00001000 /* PCI external access cache disable */ + +#define AR531XPLUS_PCI_OUT_TSTAMP (AR531XPLUS_PCI + 0x0010) + +#define AR531XPLUS_PCI_UNCACHE_CFG (AR531XPLUS_PCI + 0x0014) + +#define AR531XPLUS_PCI_IN_EN (AR531XPLUS_PCI + 0x0100) +#define AR531XPLUS_PCI_IN_EN0 0x01 /* Enable chain 0 */ +#define AR531XPLUS_PCI_IN_EN1 0x02 /* Enable chain 1 */ +#define AR531XPLUS_PCI_IN_EN2 0x04 /* Enable chain 2 */ +#define AR531XPLUS_PCI_IN_EN3 0x08 /* Enable chain 3 */ + +#define AR531XPLUS_PCI_IN_DIS (AR531XPLUS_PCI + 0x0104) +#define AR531XPLUS_PCI_IN_DIS0 0x01 /* Disable chain 0 */ +#define AR531XPLUS_PCI_IN_DIS1 0x02 /* Disable chain 1 */ +#define AR531XPLUS_PCI_IN_DIS2 0x04 /* Disable chain 2 */ +#define AR531XPLUS_PCI_IN_DIS3 0x08 /* Disable chain 3 */ + +#define AR531XPLUS_PCI_IN_PTR (AR531XPLUS_PCI + 0x0200) + +#define AR531XPLUS_PCI_OUT_EN (AR531XPLUS_PCI + 0x0400) +#define AR531XPLUS_PCI_OUT_EN0 0x01 /* Enable chain 0 */ + +#define AR531XPLUS_PCI_OUT_DIS (AR531XPLUS_PCI + 0x0404) +#define AR531XPLUS_PCI_OUT_DIS0 0x01 /* Disable chain 0 */ + +#define AR531XPLUS_PCI_OUT_PTR (AR531XPLUS_PCI + 0x0408) + +#define AR531XPLUS_PCI_INT_STATUS (AR531XPLUS_PCI + 0x0500) /* write one to clr */ +#define AR531XPLUS_PCI_TXINT 0x00000001 /* Desc In Completed */ +#define AR531XPLUS_PCI_TXOK 0x00000002 /* Desc In OK */ +#define AR531XPLUS_PCI_TXERR 0x00000004 /* Desc In ERR */ +#define AR531XPLUS_PCI_TXEOL 0x00000008 /* Desc In End-of-List */ +#define AR531XPLUS_PCI_RXINT 0x00000010 /* Desc Out Completed */ +#define AR531XPLUS_PCI_RXOK 0x00000020 /* Desc Out OK */ +#define AR531XPLUS_PCI_RXERR 0x00000040 /* Desc Out ERR */ +#define AR531XPLUS_PCI_RXEOL 0x00000080 /* Desc Out EOL */ +#define AR531XPLUS_PCI_TXOOD 0x00000200 /* Desc In Out-of-Desc */ +#define AR531XPLUS_PCI_MASK 0x0000FFFF /* Desc Mask */ +#define AR531XPLUS_PCI_EXT_INT 0x02000000 +#define AR531XPLUS_PCI_ABORT_INT 0x04000000 + +#define AR531XPLUS_PCI_INT_MASK (AR531XPLUS_PCI + 0x0504) /* same as INT_STATUS */ + +#define AR531XPLUS_PCI_INTEN_REG (AR531XPLUS_PCI + 0x0508) +#define AR531XPLUS_PCI_INT_DISABLE 0x00 /* disable pci interrupts */ +#define AR531XPLUS_PCI_INT_ENABLE 0x01 /* enable pci interrupts */ + +#define AR531XPLUS_PCI_HOST_IN_EN (AR531XPLUS_PCI + 0x0800) +#define AR531XPLUS_PCI_HOST_IN_DIS (AR531XPLUS_PCI + 0x0804) +#define AR531XPLUS_PCI_HOST_IN_PTR (AR531XPLUS_PCI + 0x0810) +#define AR531XPLUS_PCI_HOST_OUT_EN (AR531XPLUS_PCI + 0x0900) +#define AR531XPLUS_PCI_HOST_OUT_DIS (AR531XPLUS_PCI + 0x0904) +#define AR531XPLUS_PCI_HOST_OUT_PTR (AR531XPLUS_PCI + 0x0908) + + +/* + * Local Bus Interface Registers + */ +#define AR531XPLUS_LB_CONFIG (AR531XPLUS_LOCAL + 0x0000) +#define AR531XPLUS_LBCONF_OE 0x00000001 /* =1 OE is low-true */ +#define AR531XPLUS_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */ +#define AR531XPLUS_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */ +#define AR531XPLUS_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */ +#define AR531XPLUS_LBCONF_WE 0x00000010 /* =1 Write En is low-true */ +#define AR531XPLUS_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */ +#define AR531XPLUS_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */ +#define AR531XPLUS_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */ +#define AR531XPLUS_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */ +#define AR531XPLUS_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */ +#define AR531XPLUS_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */ +#define AR531XPLUS_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */ +#define AR531XPLUS_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */ +#define AR531XPLUS_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */ +#define AR531XPLUS_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */ +#define AR531XPLUS_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */ +#define AR531XPLUS_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */ +#define AR531XPLUS_LBCONF_INT 0x00020000 /* =1 Intr is low true */ +#define AR531XPLUS_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */ +#define AR531XPLUS_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */ +#define AR531XPLUS_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */ +#define AR531XPLUS_LBCONF_INT_CTR3 0x000C0000 /* GND drive, Vdd drive */ +#define AR531XPLUS_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */ +#define AR531XPLUS_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */ +#define AR531XPLUS_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */ + +#define AR531XPLUS_LB_CLKSEL (AR531XPLUS_LOCAL + 0x0004) +#define AR531XPLUS_LBCLK_EXT 0x0001 /* use external clk for lb */ + +#define AR531XPLUS_LB_1MS (AR531XPLUS_LOCAL + 0x0008) +#define AR531XPLUS_LB1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ + +#define AR531XPLUS_LB_MISCCFG (AR531XPLUS_LOCAL + 0x000C) +#define AR531XPLUS_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR531XPLUS_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */ +#define AR531XPLUS_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */ +#define AR531XPLUS_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */ +#define AR531XPLUS_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */ +#define AR531XPLUS_LBM_TIMEOUT_MASK 0x00FFFF80 +#define AR531XPLUS_LBM_TIMEOUT_SHFT 7 +#define AR531XPLUS_LBM_PORTMUX 0x07000000 + + +#define AR531XPLUS_LB_RXTSOFF (AR531XPLUS_LOCAL + 0x0010) + +#define AR531XPLUS_LB_TX_CHAIN_EN (AR531XPLUS_LOCAL + 0x0100) +#define AR531XPLUS_LB_TXEN_0 0x01 +#define AR531XPLUS_LB_TXEN_1 0x02 +#define AR531XPLUS_LB_TXEN_2 0x04 +#define AR531XPLUS_LB_TXEN_3 0x08 + +#define AR531XPLUS_LB_TX_CHAIN_DIS (AR531XPLUS_LOCAL + 0x0104) +#define AR531XPLUS_LB_TX_DESC_PTR (AR531XPLUS_LOCAL + 0x0200) + +#define AR531XPLUS_LB_RX_CHAIN_EN (AR531XPLUS_LOCAL + 0x0400) +#define AR531XPLUS_LB_RXEN 0x01 + +#define AR531XPLUS_LB_RX_CHAIN_DIS (AR531XPLUS_LOCAL + 0x0404) +#define AR531XPLUS_LB_RX_DESC_PTR (AR531XPLUS_LOCAL + 0x0408) + +#define AR531XPLUS_LB_INT_STATUS (AR531XPLUS_LOCAL + 0x0500) +#define AR531XPLUS_INT_TX_DESC 0x0001 +#define AR531XPLUS_INT_TX_OK 0x0002 +#define AR531XPLUS_INT_TX_ERR 0x0004 +#define AR531XPLUS_INT_TX_EOF 0x0008 +#define AR531XPLUS_INT_RX_DESC 0x0010 +#define AR531XPLUS_INT_RX_OK 0x0020 +#define AR531XPLUS_INT_RX_ERR 0x0040 +#define AR531XPLUS_INT_RX_EOF 0x0080 +#define AR531XPLUS_INT_TX_TRUNC 0x0100 +#define AR531XPLUS_INT_TX_STARVE 0x0200 +#define AR531XPLUS_INT_LB_TIMEOUT 0x0400 +#define AR531XPLUS_INT_LB_ERR 0x0800 +#define AR531XPLUS_INT_MBOX_WR 0x1000 +#define AR531XPLUS_INT_MBOX_RD 0x2000 + +/* Bit definitions for INT MASK are the same as INT_STATUS */ +#define AR531XPLUS_LB_INT_MASK (AR531XPLUS_LOCAL + 0x0504) + +#define AR531XPLUS_LB_INT_EN (AR531XPLUS_LOCAL + 0x0508) +#define AR531XPLUS_LB_MBOX (AR531XPLUS_LOCAL + 0x0600) + + + +/* + * IR Interface Registers + */ +#define AR531XPLUS_IR_PKTDATA (AR531XPLUS_IR + 0x0000) + +#define AR531XPLUS_IR_PKTLEN (AR531XPLUS_IR + 0x07fc) /* 0 - 63 */ + +#define AR531XPLUS_IR_CONTROL (AR531XPLUS_IR + 0x0800) +#define AR531XPLUS_IRCTL_TX 0x00000000 /* use as tranmitter */ +#define AR531XPLUS_IRCTL_RX 0x00000001 /* use as receiver */ +#define AR531XPLUS_IRCTL_SAMPLECLK_MASK 0x00003ffe /* Sample clk divisor mask */ +#define AR531XPLUS_IRCTL_SAMPLECLK_SHFT 1 +#define AR531XPLUS_IRCTL_OUTPUTCLK_MASK 0x03ffc000 /* Output clk divisor mask */ +#define AR531XPLUS_IRCTL_OUTPUTCLK_SHFT 14 + +#define AR531XPLUS_IR_STATUS (AR531XPLUS_IR + 0x0804) +#define AR531XPLUS_IRSTS_RX 0x00000001 /* receive in progress */ +#define AR531XPLUS_IRSTS_TX 0x00000002 /* transmit in progress */ + +#define AR531XPLUS_IR_CONFIG (AR531XPLUS_IR + 0x0808) +#define AR531XPLUS_IRCFG_INVIN 0x00000001 /* invert input polarity */ +#define AR531XPLUS_IRCFG_INVOUT 0x00000002 /* invert output polarity */ +#define AR531XPLUS_IRCFG_SEQ_START_WIN_SEL 0x00000004 /* 1 => 28, 0 => 7 */ +#define AR531XPLUS_IRCFG_SEQ_START_THRESH 0x000000f0 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_UNIT_SEL 0x00000100 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_WIN_SEL 0x00008000 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_WIN_THRESH 0x001f0000 /* */ +#define AR531XPLUS_IRCFG_NUM_BACKOFF_WORDS 0x01e00000 /* */ + +/* + * PCI memory constants: Memory area 1 and 2 are the same size - + * (twice the PCI_TLB_PAGE_SIZE). The definition of + * CPU_TO_PCI_MEM_SIZE is coupled with the TLB setup routine + * sysLib.c/sysTlbInit(), in that it assumes that 2 pages of size + * PCI_TLB_PAGE_SIZE are set up in the TLB for each PCI memory space. + */ + +#define CPU_TO_PCI_MEM_BASE1 0xE0000000 +#define CPU_TO_PCI_MEM_SIZE1 (2*PCI_TLB_PAGE_SIZE) + + +/* TLB attributes for PCI transactions */ + +#define PCI_MMU_PAGEMASK 0x00003FFF +#define MMU_PAGE_UNCACHED 0x00000010 +#define MMU_PAGE_DIRTY 0x00000004 +#define MMU_PAGE_VALID 0x00000002 +#define MMU_PAGE_GLOBAL 0x00000001 +#define PCI_MMU_PAGEATTRIB (MMU_PAGE_UNCACHED|MMU_PAGE_DIRTY|\ + MMU_PAGE_VALID|MMU_PAGE_GLOBAL) +#define PCI_MEMORY_SPACE1_VIRT 0xE0000000 /* Used for non-prefet mem */ +#define PCI_MEMORY_SPACE1_PHYS 0x80000000 +#define PCI_TLB_PAGE_SIZE 0x01000000 +#define TLB_HI_MASK 0xFFFFE000 +#define TLB_LO_MASK 0x3FFFFFFF +#define PAGEMASK_SHIFT 11 +#define TLB_LO_SHIFT 6 + +#define PCI_MAX_LATENCY 0xFFF /* Max PCI latency */ + +#define HOST_PCI_DEV_ID 3 +#define HOST_PCI_MBAR0 0x10000000 +#define HOST_PCI_MBAR1 0x20000000 +#define HOST_PCI_MBAR2 0x30000000 + +#define HOST_PCI_SDRAM_BASEADDR HOST_PCI_MBAR1 +#define PCI_DEVICE_MEM_SPACE 0x800000 + + +typedef unsigned int AR531X_REG; + +#define sysRegRead(phys) \ + (*(volatile AR531X_REG *)PHYS_TO_K1(phys)) + +#define sysRegWrite(phys, val) \ + ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val)) + + + +/* + * This is board-specific data that is stored in a "fixed" location in flash. + * It is shared across operating systems, so it should not be changed lightly. + * The main reason we need it is in order to extract the ethernet MAC + * address(es). + */ +struct ar531x_boarddata { + u32 magic; /* board data is valid */ +#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */ + u16 cksum; /* checksum (starting with BD_REV 2) */ + u16 rev; /* revision of this struct */ +#define BD_REV 4 + char boardName[64]; /* Name of board */ + u16 major; /* Board major number */ + u16 minor; /* Board minor number */ + u32 config; /* Board configuration */ +#define BD_ENET0 0x00000001 /* ENET0 is stuffed */ +#define BD_ENET1 0x00000002 /* ENET1 is stuffed */ +#define BD_UART1 0x00000004 /* UART1 is stuffed */ +#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */ +#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */ +#define BD_SYSLED 0x00000020 /* System LED stuffed */ +#define BD_EXTUARTCLK 0x00000040 /* External UART clock */ +#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */ +#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */ +#define BD_WLAN0 0x00000200 /* Enable WLAN0 */ +#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */ +#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */ +#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */ +#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */ +#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */ +#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */ +#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */ +#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */ + u16 resetConfigGpio; /* Reset factory GPIO pin */ + u16 sysLedGpio; /* System LED GPIO pin */ + + u32 cpuFreq; /* CPU core frequency in Hz */ + u32 sysFreq; /* System frequency in Hz */ + u32 cntFreq; /* Calculated C0_COUNT frequency */ + + u8 wlan0Mac[6]; + u8 enet0Mac[6]; + u8 enet1Mac[6]; + + u16 pciId; /* Pseudo PCIID for common code */ + u16 memCap; /* cap bank1 in MB */ + + /* version 3 */ + u8 wlan1Mac[6]; /* (ar5212) */ +}; + +#endif + +#endif /* AR531X_H */ diff --git a/package/fonera-mp3-drv/src/ar531xlnx.h b/package/fonera-mp3-drv/src/ar531xlnx.h new file mode 100644 index 000000000..fe0333f55 --- /dev/null +++ b/package/fonera-mp3-drv/src/ar531xlnx.h @@ -0,0 +1,140 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * This file contains definitions needed in order to compile + * AR531X products for linux. Definitions that are largely + * AR531X-specific and independent of operating system belong + * in ar531x.h rather than this file. + */ +#ifndef __AR531XLNX_H +#define __AR531XLNX_H +#include "ar531x.h" + +#define AR531X_HIGH_PRIO 0x10 +#define AR531X_MISC_IRQ_BASE 0x20 +#define AR531X_GPIO_IRQ_BASE 0x30 + +/* Software's idea of interrupts handled by "CPU Interrupt Controller" */ +#ifndef CONFIG_AR531X_COBRA +#define CONFIG_AR531X_COBRA 0 +#endif + +#if CONFIG_AR531X_COBRA +#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 +#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ +#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ +#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ +#define AR531X_IRQ_LCBUS_PCI MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ +#define AR531X_IRQ_WLAN0_POLL MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ +#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ +#else +#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 +#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ +#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ +#define AR531X_IRQ_ENET1_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ +#define AR531X_IRQ_WLAN1_INTRS MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */ +#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ +#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ +#endif + +/* Miscellaneous interrupts, which share IP6 or IP2 */ +#define AR531X_MISC_IRQ_NONE AR531X_MISC_IRQ_BASE+0 +#define AR531X_MISC_IRQ_TIMER AR531X_MISC_IRQ_BASE+1 +#define AR531X_MISC_IRQ_AHB_PROC AR531X_MISC_IRQ_BASE+2 +#define AR531X_MISC_IRQ_AHB_DMA AR531X_MISC_IRQ_BASE+3 +#define AR531X_MISC_IRQ_GPIO AR531X_MISC_IRQ_BASE+4 +#define AR531X_MISC_IRQ_UART0 AR531X_MISC_IRQ_BASE+5 +#define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6 +#define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7 +#define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8 +#define AR531X_MISC_IRQ_COUNT 9 + +/* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */ +#define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0 +#define AR531X_GPIO_IRQ(n) AR531X_MISC_IRQ_BASE+(n)+1 +#define AR531X_GPIO_IRQ_COUNT 9 + +#define PHYS_TO_K1(physaddr) KSEG1ADDR(physaddr) +//#define PHYS_TO_K0(physaddr) KSEG0ADDR(physaddr) +#define UNMAPPED_TO_PHYS(vaddr) PHYSADDR(vaddr) +#define IS_UNMAPPED_VADDR(vaddr) \ + ((KSEGX(vaddr) == KSEG0) || (KSEGX(vaddr) == KSEG1)) + +/* IOCTL commands for /proc/ar531x */ +#define AR531X_CTRL_DO_BREAKPOINT 1 +#define AR531X_CTRL_DO_MADWIFI 2 + +/* + * Definitions for operating system portability. + * These are vxWorks-->Linux translations. + */ +#define LOCAL static +#define BOOL int +#define TRUE 1 +#define FALSE 0 +#define UINT8 u8 +#define UINT16 u16 +#define UINT32 u32 +#define PRINTF printk +#if /* DEBUG */ 1 +#define DEBUG_PRINTF printk +#define printf printk +#define INLINE +#else +DEBUG_PRINTF while (0) printk +#define INLINE inline +#endif +#define sysUDelay(usecs) udelay(usecs) +#define sysMsDelay(msecs) mdelay(msecs) +typedef volatile UINT8 *VIRT_ADDR; +#define MALLOC(sz) kmalloc(sz, GFP_KERNEL) +#define MALLOC_NOSLEEP(sz) kmalloc(sz, GFP_ATOMIC) +#define FREE(ptr) kfree((void *)ptr) +#define BSP_BUG() do { printk("kernel BSP BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) +#define BSP_BUG_ON(condition) do { if (unlikely((condition)!=0)) BSP_BUG(); } while(0) +#define ASSERT(x) BSP_BUG_ON(!(x)) + +extern struct ar531x_boarddata *ar531x_board_configuration; +extern char *ar531x_radio_configuration; +extern char *enet_mac_address_get(int MACUnit); + +extern void kgdbInit(void); +extern int kgdbEnabled(void); +extern void breakpoint(void); +extern int kgdbInterrupt(void); +extern unsigned int ar531x_cpu_frequency(void); +extern unsigned int ar531x_sys_frequency(void); + +/* GPIO support */ +extern struct irqaction spurious_gpio; +extern unsigned int gpioIntMask; +extern void ar531x_gpio_intr_init(int irq_base); +extern void ar531x_gpio_ctrl_output(int gpio); +extern void ar531x_gpio_ctrl_input(int gpio); +extern void ar531x_gpio_set(int gpio, int val); +extern int ar531x_gpio_get(int gpio); +extern void ar531x_gpio_intr_enable(unsigned int irq); +extern void ar531x_gpio_intr_disable(unsigned int irq); + +/* Watchdog Timer support */ +extern int watchdog_start(unsigned int milliseconds); +extern int watchdog_stop(void); +extern int watchdog_is_enabled(void); +extern unsigned int watchdog_min_timer_reached(void); +extern void watchdog_notify_alive(void); + +#define A_DATA_CACHE_INVAL(start, length) \ + dma_cache_inv((UINT32)(start),(length)) + +#define sysWbFlush() mb() + +#define intDisable(x) cli() +#define intEnable(x) sti() + +#endif /* __AR531XLNX_H */ diff --git a/package/fonera-mp3-drv/src/mp3_drv.c b/package/fonera-mp3-drv/src/mp3_drv.c new file mode 100644 index 000000000..f2c0dd166 --- /dev/null +++ b/package/fonera-mp3-drv/src/mp3_drv.c @@ -0,0 +1,308 @@ +/* +* a.lp_mp3 - VS1011B driver for Fonera +* Copyright (c) 2007 phrozen.org - John Crispin <john@phrozen.org> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... john@phrozen.org +* +*/ + + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/genhd.h> + +// do we want debuging info ? +#if 0 +#define DBG(x) x +#else +#define DBG(x) +#endif + +#define MP3_CHUNK_SIZE 4096 +#define MP3_BUFFERING 0 +#define MP3_PLAYING 1 +#define MP3_BUFFER_FINISHED 2 +#define MP3_PLAY_FINISHED 3 +typedef struct _MP3_DATA{ + unsigned char mp3[MP3_CHUNK_SIZE]; + unsigned char state; +} MP3_DATA; + +#define IOCTL_MP3_INIT 0x01 +#define IOCTL_MP3_RESET 0x02 +#define IOCTL_MP3_SETVOLUME 0x03 +#define IOCTL_MP3_GETVOLUME 0x04 + +typedef struct _AUDIO_DATA{ + unsigned int bitrate; + unsigned int sample_rate; + unsigned char is_stereo; +}AUDIO_DATA; +#define IOCTL_MP3_GETAUDIODATA 0x05 +#define IOCTL_MP3_CLEARBUFFER 0x06 +#define IOCTL_MP3_PLAY 0x07 + +typedef struct _MP3_BEEP{ + unsigned char freq; + unsigned int ms; +} MP3_BEEP; +#define IOCTL_MP3_BEEP 0x08 +#define IOCTL_MP3_END_REACHED 0x09 +#define IOCTL_MP3_BASS 0x10 + +#define CRYSTAL12288 0x9800 +#define CRYSTAL24576 0x0 + +#define DEV_NAME "mp3" +#define DEV_MAJOR 196 +#define MAX_MP3_COUNT 1 + +typedef struct _mp3_inf{ + unsigned char is_open; +} mp3_inf; +static mp3_inf mp3_info[MAX_MP3_COUNT]; + +#define MP3_BUFFER_SIZE (128 * 1024) +unsigned char mp3_buffer[MP3_BUFFER_SIZE]; + +static unsigned long int mp3_buffer_offset_write = 0; +static unsigned long int mp3_buffer_offset_read = 0; +static unsigned char mp3_buffering_status = MP3_BUFFERING; +static unsigned long int mp3_data_in_buffer = 0; +static int mp3_thread = 0; +unsigned int crystal_freq; + +#include "vs10xx.c" + +static wait_queue_head_t wq; +static DECLARE_COMPLETION(mp3_exit); + +static int mp3_playback_thread(void *data){ + int j; + unsigned long timeout; + printk("started kthread\n"); + daemonize("kmp3"); + while(mp3_buffering_status != MP3_PLAY_FINISHED){ + if((mp3_buffering_status == MP3_PLAYING) || (mp3_buffering_status == MP3_BUFFER_FINISHED)){ + while(VS1011_NEEDS_DATA){ + if(mp3_buffer_offset_read == MP3_BUFFER_SIZE){ + mp3_buffer_offset_read = 0; + } + + if(mp3_data_in_buffer == 0){ + if(mp3_buffering_status == MP3_BUFFER_FINISHED){ + printk("mp3_drv.ko : finished playing\n"); + mp3_buffering_status = MP3_PLAY_FINISHED; + } else { + printk("mp3_drv.ko : buffer empty ?\n"); + if(mp3_buffering_status != MP3_PLAY_FINISHED){ + } + } + } else { + for(j = 0; j < 32; j++){ + VS1011_send_SDI(mp3_buffer[mp3_buffer_offset_read + j]); + } + mp3_buffer_offset_read += 32; + mp3_data_in_buffer -= 32; + } + } + } + timeout = 1; + timeout = wait_event_interruptible_timeout(wq, (timeout==0), timeout); + } + complete_and_exit(&mp3_exit, 0); +} + +static ssize_t module_write(struct file * file, const char * buffer, size_t count, loff_t *offset){ + MP3_DATA mp3_data; + + copy_from_user((char*) &mp3_data, buffer, sizeof(MP3_DATA)); + + if(mp3_data.state == MP3_BUFFER_FINISHED){ + mp3_buffering_status = MP3_BUFFER_FINISHED; + DBG(printk("mp3_drv.ko : file end reached\n")); + return 1; + } + + if(mp3_data.state == MP3_PLAY_FINISHED){ + mp3_buffering_status = MP3_PLAY_FINISHED; + mp3_data_in_buffer = 0; + DBG(printk("mp3_drv.ko : stop playing\n")); + return 1; + } + + if(mp3_data_in_buffer + MP3_CHUNK_SIZE >= MP3_BUFFER_SIZE){ + DBG(printk("mp3_drv.ko : buffer is full? %ld\n", mp3_data_in_buffer);) + return 0; + } + + if(mp3_buffer_offset_write == MP3_BUFFER_SIZE){ + mp3_buffer_offset_write = 0; + } + + memcpy(&mp3_buffer[mp3_buffer_offset_write], mp3_data.mp3, MP3_CHUNK_SIZE); + mp3_buffer_offset_write += MP3_CHUNK_SIZE; + mp3_buffering_status = mp3_data.state; + mp3_data_in_buffer += MP3_CHUNK_SIZE; + return 1; +} + +static int module_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){ + unsigned int retval = 0; + AUDIO_DATA audio_data; + MP3_BEEP mp3_beep; + DBG(printk("mp3_drv.ko : Ioctl Called (cmd=%d)\n", cmd );) + switch (cmd) { + case IOCTL_MP3_INIT: + crystal_freq = arg; + VS1011_init(crystal_freq, 1); + VS1011_print_registers(); + break; + + case IOCTL_MP3_RESET: + DBG(printk("mp3_drv.ko : doing a sw reset\n");) + VS1011_init(crystal_freq, 0); + VS1011_print_registers(); + VS1011_send_zeros(0x20); + break; + + case IOCTL_MP3_SETVOLUME: + DBG(printk("mp3_drv.ko : setting volume to : %lu\n", arg&0xffff);) + VS1011_set_volume(arg); + break; + + case IOCTL_MP3_GETVOLUME: + retval = VS1011_get_volume(); + DBG(printk("mp3_drv.ko : read volume : %d\n", retval);) + break; + + case IOCTL_MP3_GETAUDIODATA: + DBG(printk("mp3_drv.ko : read audio data\n");) + VS1011_get_audio_data(&audio_data); + copy_to_user((char*)arg, (char*)&audio_data, sizeof(AUDIO_DATA)); + break; + + case IOCTL_MP3_CLEARBUFFER: + DBG(printk("mp3_drv.ko : clearing buffer\n");) + mp3_buffer_offset_read = 0; + mp3_buffer_offset_write = 0; + mp3_buffering_status = MP3_PLAY_FINISHED; + mp3_data_in_buffer = 0; + break; + + case IOCTL_MP3_PLAY: + mp3_thread = kernel_thread(mp3_playback_thread, NULL, CLONE_KERNEL); + break; + + case IOCTL_MP3_BEEP: + copy_from_user((char*)&mp3_beep, (char*)arg, sizeof(MP3_BEEP)); + VS1011_sine(1,mp3_beep.freq); + msDelay(mp3_beep.ms); + VS1011_sine(0,0); + break; + + case IOCTL_MP3_END_REACHED: + if(mp3_buffering_status == MP3_PLAY_FINISHED){ + retval = 1; + } + break; + + case IOCTL_MP3_BASS: + VS1011_set_bass(arg); + break; + + default: + printk("mp3_drv.ko : unknown ioctl\n"); + break; + + } + return retval; +} + +static int module_open(struct inode *inode, struct file *file){ + unsigned int dev_minor = MINOR(inode->i_rdev); + if(dev_minor != 0){ + printk("mp3_drv.ko : trying to access unknown minor device -> %d\n", dev_minor); + return -ENODEV; + } + if(mp3_info[dev_minor].is_open) { + printk("mp3_drv.ko : Device with minor ID %d already in use\n", dev_minor); + return -EBUSY; + } + mp3_info[dev_minor].is_open = 1; + + mp3_buffering_status = MP3_PLAY_FINISHED; + printk("mp3_drv.ko : Minor %d has been opened\n", dev_minor); + return 0; +} + +static int module_close(struct inode * inode, struct file * file){ + unsigned int dev_minor = MINOR(inode->i_rdev); + mp3_info[dev_minor].is_open = 0; + printk("mp3_drv.ko : Minor %d has been closed\n", dev_minor); + mp3_buffering_status = MP3_PLAY_FINISHED; + return 0; +} + +struct file_operations modulemp3_fops = { + write: module_write, + ioctl: module_ioctl, + open: module_open, + release: module_close +}; + +static int __init mod_init(void){ + printk("mp3_drv.ko : VS1011b Driver\n"); + printk("mp3_drv.ko : Made by John '2B|!2B' Crispin (john@phrozen.org)\n"); + printk("mp3_drv.ko : Starting ...\n"); + + if(register_chrdev(DEV_MAJOR, DEV_NAME, &modulemp3_fops)) { + printk( "mp3_drv.ko : Error whilst opening %s (%d)\n", DEV_NAME, DEV_MAJOR); + return( -ENODEV ); + } + + mp3_info[0].is_open = 0; + printk("mp3_drv.ko : Device %s registered for major ID %d\n", DEV_NAME, DEV_MAJOR); + crystal_freq = CRYSTAL12288; + VS1011_init(crystal_freq, 1); + VS1011_print_registers(); + printk("end of init\n"); + init_waitqueue_head(&wq); + printk("wait queue started\n"); + return 0; +} + +static void __exit mod_exit(void){ + printk( "mp3_drv.ko : Cleanup\n" ); + unregister_chrdev(DEV_MAJOR, DEV_NAME); +} + +module_init (mod_init); +module_exit (mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("K. John '2B|!2B' Crispin"); +MODULE_DESCRIPTION("vs1011 Driver for Fox Board"); + + + diff --git a/package/fonera-mp3-drv/src/vs10xx.c b/package/fonera-mp3-drv/src/vs10xx.c new file mode 100644 index 000000000..e7b7f68c1 --- /dev/null +++ b/package/fonera-mp3-drv/src/vs10xx.c @@ -0,0 +1,328 @@ +/* + * a.lp_mp3 - VS1011B driver for Fonera + * Copyright (c) 2007 phrozen.org - John Crispin <john@phrozen.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA + * + * Feedback, Bugs.... mail john@phrozen.org + * + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <asm/io.h> +#include <asm/system.h> +#include <asm/irq.h> +#include "ar531xlnx.h" + +#define AR5315_DSLBASE 0xB1000000 +#define AR5315_GPIO_DI (AR5315_DSLBASE + 0x0088) +#define AR5315_GPIO_DO (AR5315_DSLBASE + 0x0090) +#define AR5315_GPIO_CR (AR5315_DSLBASE + 0x0098) +#define AR5315_GPIO_INT (AR5315_DSLBASE + 0x00a0) + +#define GPIO_0 1<<0 +#define GPIO_1 1<<1 +#define GPIO_2 1<<2 +#define GPIO_3 1<<3 +#define GPIO_4 1<<4 +#define GPIO_6 1<<6 +#define GPIO_7 1<<7 + +#define DREQ ((unsigned int)GPIO_7) +#define SCK ((unsigned int)GPIO_1) +#define SI ((unsigned int)GPIO_4) +#define BSYNC ((unsigned int)GPIO_3) +#define CS ((unsigned int)GPIO_0) +#define SO ((unsigned int)GPIO_6) +#define RES ((unsigned int)GPIO_2) + +#define REG_MODE 0x0 +#define REG_STATUS 0x1 +#define REG_BASS 0x2 +#define REG_CLOCKF 0x3 +#define REG_DECODETIME 0x4 +#define REG_AUDATA 0x5 +#define REG_WRAM 0x6 +#define REG_WRAMADDR 0x7 +#define REG_HDAT0 0x8 +#define REG_HDAT1 0x9 +#define REG_A1ADDR 0xa +#define REG_VOL 0xb +#define REG_A1CTRL0 0xc +#define REG_A1CTRL1 0xd +#define REG_A1CTRL2 0xe + +#define VS1011_NEEDS_DATA spi_get_bit(DREQ) +#define VS1011_NEEDS_NO_DATA (spi_get_bit(DREQ)== 0x00) +#define VS1011_WHILE_NEEDS_NO_DATA while(spi_get_bit(DREQ)== 0x00){} + +#define VS_CS_LO spi_clear_bit(CS) +#define VS_CS_HI spi_set_bit(CS) + +#define VS_BSYNC_LO spi_clear_bit(BSYNC) +#define VS_BSYNC_HI spi_set_bit(BSYNC) + +#define VS_RESET_LO spi_clear_bit(RES) +#define VS_RESET_HI spi_set_bit(RES) + +#define VS1011_READ SPI_io_vs1011b(0x03) +#define VS1011_WRITE SPI_io_vs1011b(0x02) + +void msDelay(int ms) { + int i,a; + int delayvar=10; + + for (a=0;a<ms;a++) { + for (i=0;i<33084;i++) { + delayvar*=2; + delayvar/=2; + } + } +} + +int spi_get_bit(unsigned int pin){ + return ((sysRegRead(AR5315_GPIO_DI)&pin)?(1):(0)); +} + +void spi_set_bit(unsigned int pin){ + sysRegWrite(AR5315_GPIO_DO, (sysRegRead(AR5315_GPIO_DO) | pin)); +} + +void spi_clear_bit(unsigned int pin){ + sysRegWrite(AR5315_GPIO_DO, (sysRegRead(AR5315_GPIO_DO) & ~pin)); +} + +void SPI_clock_vs1011b(void){ + spi_clear_bit(SCK); + spi_set_bit(SCK); +} + +unsigned char SPI_io_vs1011b(unsigned char byte){ + int i; + unsigned char this_bit; + unsigned char byte_out = 0; + for(i = 7; i>=0; i--){ + if(byte & (1<<i)){ + this_bit = 1; + } else { + this_bit = 0; + } + if(this_bit){ + spi_set_bit(SI); + } else { + spi_clear_bit(SI); + } + SPI_clock_vs1011b(); + byte_out += spi_get_bit(SO)<<i; + } + return byte_out; +} + +void SPI_init_vs1011(void){ + sysRegWrite(AR5315_GPIO_CR, (sysRegRead(AR5315_GPIO_CR) | SI | SCK | CS | BSYNC | RES) & ~(SO|DREQ)); + spi_clear_bit(SCK); + spi_clear_bit(SI); + VS_CS_HI; + VS_BSYNC_HI; +} + +void VS1011_send_SCI(unsigned char reg, unsigned int data){ + VS_CS_LO; + VS1011_WRITE; + SPI_io_vs1011b(reg); + SPI_io_vs1011b((data>>8)&0xff); + SPI_io_vs1011b(data&0xff); + VS_CS_HI; +} + +unsigned int VS1011_read_SCI(unsigned char reg){ + unsigned int data; + VS_CS_LO; + VS1011_READ; + SPI_io_vs1011b(reg); + data = 0; + data = SPI_io_vs1011b(0x00); + data <<= 8; + data += SPI_io_vs1011b(0x00); + VS_CS_HI; + return data; +} + +void VS1011_send_SDI(unsigned char byte){ + int i; + VS_BSYNC_LO; + for(i = 7; i>=0; i--){ + if(byte & (1<<i)){ + spi_set_bit(SI); + + } else { + spi_clear_bit(SI); + } + spi_clear_bit(SCK); + spi_set_bit(SCK); + } + VS_BSYNC_HI; +} + +void VS1011_send_SDI_32(unsigned char* data){ + int i; + VS1011_WHILE_NEEDS_NO_DATA; + for(i=0; i<32; i++){ + VS1011_send_SDI(data[i]); + } +} + +void VS1011_send_zeros(unsigned char count){ + do{ + VS1011_send_SDI(0x0); + count--; + }while(count); +} + +void VS1011_set_volume(unsigned int vol){ + VS1011_send_SCI(REG_VOL, vol); +} + +void VS1011_SW_reset(unsigned int _crystal_freq){ + unsigned int regval = 0x0804; + unsigned long int i = 0; + msDelay(100); + VS1011_send_zeros(32); + VS1011_send_SCI(REG_MODE, regval); + msDelay(10); + while((VS1011_NEEDS_NO_DATA) && (i++<0xffff)){}; + VS1011_send_SCI(REG_CLOCKF, _crystal_freq); + VS1011_send_zeros(16); + VS1011_set_volume(0x00); +} + +void VS1011_HW_reset(void){ + + VS_RESET_LO; + msDelay(1); + VS_RESET_HI; + msDelay(1); +} + +void VS1011_init(unsigned int _crystal_freq, unsigned char hw){ + if(hw){ + SPI_init_vs1011(); + } + printk("mp3_drv.ko : Init start\n"); + if(hw){ + VS1011_HW_reset(); + } + VS1011_SW_reset(_crystal_freq); + printk("mp3_drv.ko : init_ok\n"); +} + +void VS1011_sine(unsigned char state, unsigned char freq){ + VS1011_send_zeros(16); + if(state == 0x01){ + VS1011_send_SDI(0x53); + VS1011_send_SDI(0xEF); + VS1011_send_SDI(0x6E); + VS1011_send_SDI(freq); + VS1011_send_zeros(0x04); + } else { + VS1011_send_SDI(0x45); + VS1011_send_SDI(0x78); + VS1011_send_SDI(0x69); + VS1011_send_SDI(0x74); + VS1011_send_zeros(0x04); + } +} + +unsigned int VS1011_get_volume(void){ + return VS1011_read_SCI(REG_VOL); +} + +unsigned int VS1011_get_decode_time(void){ + return VS1011_read_SCI(REG_DECODETIME); +} + +const unsigned int sample_rate_values[] = {0, 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000}; + +void VS1011_get_audio_data(AUDIO_DATA* audio){ + unsigned int audata = VS1011_read_SCI(REG_AUDATA); + audio->sample_rate = sample_rate_values[(audata&0x1E00)>>9]; + audio->bitrate = audata&0x1FF; + audio->is_stereo = (audata&0x8000)>>15; +} + +void VS1011_print_registers(void){ + unsigned char i; + for(i = 0; i< 14; i++){ + unsigned int regval = VS1011_read_SCI(i); + printk("mp3_drv.ko : %d \n", regval); + } +} + +void VS1011_volume(unsigned char left, unsigned char right){ + unsigned int regval = left; + regval <<=8; + regval += right; + VS1011_send_SCI(REG_VOL, regval); +} + +void VS1011_set_bass(unsigned int regval){ + VS1011_send_SCI(REG_BASS, regval); +} + +void VS1011_set_reg(unsigned int reg, unsigned int regval){ + VS1011_send_SCI(reg, regval); +} + +/* +int vs_test(void) { + SPI_init_vs1011(); + printk("%u\n", *R_GEN_CONFIG); + VS1001_init(_crystal_freq); + VS1001_print_registers(); + VS1001_volume(0x30, 0x30); + msDelay(1000); + VS1001_sine(1, 0x30); + msDelay(1000); + VS1001_sine(0, 0); + VS1001_send_zeros(0x20); + msDelay(1000); + VS1001_sine(1, 0x30); + msDelay(1000); + VS1001_sine(0, 0); + VS1001_send_zeros(0x20); + msDelay(1000); + VS1001_sine(1, 0x30); + msDelay(1000); + VS1001_sine(0, 0); + + AUDIO_DATA a; + VS1001_get_audio_data(&a); + printk("mp3_drv.ko : rate : %d, bit : %d, stereo : %d \n", a.sample_rate, a.bitrate, a.is_stereo); + VS1001_SW_reset(_crystal_freq); + return 0; +}*/ + diff --git a/package/fonera-mp3/Makefile b/package/fonera-mp3/Makefile new file mode 100644 index 000000000..b807100b4 --- /dev/null +++ b/package/fonera-mp3/Makefile @@ -0,0 +1,58 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# $Id: Makefile 8444 2007-08-20 16:12:24Z nbd $ + +include $(TOPDIR)/rules.mk + +PKG_NAME:=fonera-mp3d +PKG_RELEASE:=1 +PKG_VERSION:=1.0 +PKG_BUILD_DEPENDS:=json-c + +include $(INCLUDE_DIR)/package.mk + +define Package/fonera-mp3d + SECTION:=utils + CATEGORY:=Utilities + DEPENDS:=@LINUX_2_6_ATHEROS + TITLE:=Daemon for fonera-mp3 + DESCRIPTION:=Daemon to drive a vs1011X mp3 decoder attached to the \ + fonera gpio pins +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + $(TARGET_CONFIGURE_OPTS) \ + CFLAGS="$(TARGET_CFLAGS)" + $(MAKE) -C $(PKG_BUILD_DIR)/cgi \ + $(TARGET_CONFIGURE_OPTS) \ + CFLAGS="$(TARGET_CFLAGS) -I $(STAGING_DIR)/usr/include/json" \ + LDLIBS="$(STAGING_DIR)/usr/lib/libjson.a" + $(MAKE) -C $(PKG_BUILD_DIR)/cli \ + $(TARGET_CONFIGURE_OPTS) \ + CFLAGS="$(TARGET_CFLAGS)" +endef + +define Package/fonera-mp3d/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/mp3d $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cli/mplay $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/www/cgi-bin + $(INSTALL_DIR) $(1)/www/local + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cgi/{stylesheet.css,json.js} $(1)/www/local + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cgi/mp3.cgi $(1)/www/cgi-bin + ln -s mp3.cgi $(1)/www/cgi-bin/mp3_cmd.cgi + ln -s mp3.cgi $(1)/www/cgi-bin/mp3_json.cgi + ln -s mp3.cgi $(1)/www/cgi-bin/mp3_remote.cgi +endef + +$(eval $(call BuildPackage,fonera-mp3d)) diff --git a/package/fonera-mp3/src/Makefile b/package/fonera-mp3/src/Makefile new file mode 100644 index 000000000..350f84855 --- /dev/null +++ b/package/fonera-mp3/src/Makefile @@ -0,0 +1,24 @@ +PROGS = mp3d + +INSTDIR = $(prefix)/usr/bin +INSTMODE = 0755 +INSTOWNER = root +INSTGROUP = root + +OBJS = mp3_main.o lib/mp3_states.o lib/mp3_common.o lib/mp3_stream.o \ + lib/mp3_file.o lib/mp3_nix_socket.o lib/mp3_socket_parser.o \ + lib/mp3_misc.o lib/mp3_playtime.o lib/mp3_tcp_socket.o + +all: $(PROGS) +$(PROGS): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ + $(STRIP) $@ + +install: $(PROGS) + $(INSTALL) -d $(INSTDIR) + $(INSTALL) -m $(INSTMODE) -o $(INSTOWNER) -g $(INSTGROUP) $(PROGS) $(INSTDIR) + +clean: + rm -f $(PROGS) *.o core + rm -f lib/$(PROGS) lib/*.o liob/core + diff --git a/package/fonera-mp3/src/cgi/Makefile b/package/fonera-mp3/src/cgi/Makefile new file mode 100644 index 000000000..b8119c043 --- /dev/null +++ b/package/fonera-mp3/src/cgi/Makefile @@ -0,0 +1,13 @@ +PROGS = mp3.cgi + +OBJS = main.o + + +all: $(PROGS) +$(PROGS): + $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $(PROGS) main.c $(LDLIBS) + $(STRIP) $(PROGS) + +clean: + rm -f $(PROGS) *.o core + diff --git a/package/fonera-mp3/src/cgi/json.h b/package/fonera-mp3/src/cgi/json.h new file mode 100644 index 000000000..a5a3432b2 --- /dev/null +++ b/package/fonera-mp3/src/cgi/json.h @@ -0,0 +1,31 @@ +/* + * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _json_h_ +#define _json_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bits.h" +#include "debug.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_util.h" +#include "json_object.h" +#include "json_tokener.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/package/fonera-mp3/src/cgi/json.js b/package/fonera-mp3/src/cgi/json.js new file mode 100644 index 000000000..721d5273e --- /dev/null +++ b/package/fonera-mp3/src/cgi/json.js @@ -0,0 +1,141 @@ +var alpmp3_playtime = 0; +var alpmp3_state = 0; +var alpmp3_ip = ""; +var obj_volume; +var obj_bass; +var obj_playtime; +var obj_sate; +var obj_filename; +var MP3Object; +var is_setup = 0; + +function alpmp3_ajax_new_data(){ + obj_bass.firstChild.nodeValue = MP3Object.alpmp3.bass; + obj_volume.firstChild.nodeValue = MP3Object.alpmp3.volume; + obj_state.firstChild.nodeValue = MP3Object.alpmp3.type; + obj_filename.firstChild.nodeValue = MP3Object.alpmp3.filename; + alpmp3_state = MP3Object.alpmp3.state; + if(Math.abs(alpmp3_playtime - MP3Object.alpmp3.playtime) > 1){ + alpmp3_playtime = MP3Object.alpmp3.playtime; + } +} + +function alpmp3_update_data(url){ + var data; + var http_request = new XMLHttpRequest(); + http_request.open("GET", url, true); + http_request.onreadystatechange = function () { + if (http_request.readyState == 4) { + if (http_request.status == 200) { + MP3Object = eval("(" + http_request.responseText + ")"); + alpmp3_ajax_new_data(); + } else { + alert("There was a problem with the URL."); + } + http_request = null; + } + } + http_request.send(null); + self.setTimeout("alpmp3_update_data('mp3_json.cgi');", 4000); +} + +function alpmp3_remote(cmd){ + var doit = ""; + switch(cmd){ + case 'volup': + if(MP3Object.alpmp3.volume < 30){ + MP3Object.alpmp3.volume++; + } + doit = "?vol=" + MP3Object.alpmp3.volume; + break; + case 'voldown': + if(MP3Object.alpmp3.volume > 0){ + MP3Object.alpmp3.volume--; + } + doit = "?vol=" + MP3Object.alpmp3.volume; + break; + case 'bassup': + if(MP3Object.alpmp3.bass < 30){ + MP3Object.alpmp3.bass++; + } + doit = "?bass=" + MP3Object.alpmp3.bass; + break; + case 'bassdown': + if(MP3Object.alpmp3.volume < 30){ + MP3Object.alpmp3.bass--; + } + doit = "?bass=" + MP3Object.alpmp3.bass; + break; + case 'stop': + doit = "?stop=1"; + break; + case 'start': + doit = "?start=1"; + break; + case 'next': + doit = "?next=1"; + break; + case 'back': + doit = "?back=1"; + break; + } + if(doit != ""){ + var http_request2 = new XMLHttpRequest(); + http_request2.open("GET", 'mp3_cmd.cgi'+doit, true); + http_request2.onreadystatechange = function () { + if (http_request2.readyState == 4) { + if (http_request2.status == 200) { + alpmp3_ajax_new_data(); + } else { + alert("There was a problem with the URL."); + } + http_request2 = null; + } + } + http_request2.send(null); + } + +} + +function alpmp3_timeout(){ + alpmp3_state = 0; + alert(alpmp3_playtime); +} + +function alpmp3_playtime_update(){ + self.setTimeout("alpmp3_playtime_update()", 1000); + if(alpmp3_state > 0){ + alpmp3_playtime ++; + } else { + alpmp3_playtime = 0; + } + var s = alpmp3_playtime; + var h = 0; + var m = 0; + while(s > 3599){ + h++; + s -= 3600; + } + while(s > 59){ + m++; + s -= 60; + } + ptime = ((m < 10) ? "0" : "") + m + ":" + ((s < 10) ? "0" : "") + s; + if(h > 0){ + ptime = ((h < 10) ? "0" : "") + h + ":" + ptime; + } + obj_playtime.firstChild.nodeValue = ptime; +} + +function alpmp3_setup($ip){ + if(is_setup == 0){ + obj_volume = document.getElementById("alpmp3_volume"); + obj_bass = document.getElementById("alpmp3_bass"); + obj_state = document.getElementById("alpmp3_state"); + obj_filename = document.getElementById("alpmp3_filename"); + obj_playtime = document.getElementById("alpmp3_playtime"); + is_setup = 1; + } + self.setTimeout("alpmp3_update_data('mp3_json.cgi');", 4000); + self.setTimeout("alpmp3_playtime_update()", 1000); +} diff --git a/package/fonera-mp3/src/cgi/main.c b/package/fonera-mp3/src/cgi/main.c new file mode 100644 index 000000000..0499e0eee --- /dev/null +++ b/package/fonera-mp3/src/cgi/main.c @@ -0,0 +1,237 @@ +/* +* FOXMP3 +* Copyright (c) 2007 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netdb.h> + +#include <json.h> + +#define SOCKET_PATH "/tmp/foxmp3" + +void print_http_header(){ + printf("Content-type: text/html\n\n"); +} + +int read_parameter(char *name, char *value, int maxlen){ + char *pos1, *pos2; + char *query_string = getenv("QUERY_STRING"); + int success = 0; + + if(query_string){ + pos1 = strstr(query_string, name); + if(pos1){ + pos1 += strlen(name) + 1; + pos2 = strstr(pos1, "&"); + if(pos2){ + *pos2 = '\0'; + } + if(strlen(pos1) >= maxlen){ + pos1[maxlen] = '\0'; + } + strcpy(value, pos1); + success = 1; + } + } + return success; +} + + +int issue_command(unsigned char *str){ + int s, t, len; + struct sockaddr_un remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + exit(1); + } + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCKET_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + return 1; + } + if (send(s, str, strlen(str), 0) == -1) { + return 1; + } + unsigned char loop = 1; + while(loop){ + if ((t=recv(s, str, 2048, 0)) > 0) { + str[t] = '\0'; + if((strstr(str, "OK\n")) || (strstr(str, "ERROR\n"))){ + loop = 0; + } + } else { + return 1; + } + } + close(s); + return 0; +} + +void handle_cmd(){ + unsigned char param[128]; + unsigned char cmd[256]; + int i; + *cmd = '\0'; + if(read_parameter("vol", param, 128)){ + i = atoi(param); + i = 120 - (i * 4); + sprintf(cmd, "VOLUME %d", i); + } + if(read_parameter("bass", param, 128)){ + i = atoi(param); + sprintf(cmd, "BASS %d", i); + } + if(read_parameter("start", param, 128)){ + sprintf(cmd, "START"); + } + if(read_parameter("stop", param, 128)){ + sprintf(cmd, "STOP"); + } + if(read_parameter("next", param, 128)){ + sprintf(cmd, "NEXT"); + } + if(read_parameter("back", param, 128)){ + sprintf(cmd, "BACK"); + } + if(*cmd){ + issue_command(cmd); + } +} + +void print_html_remote(){ + char name[128]; + gethostname(name, 128); + printf("<html><head><title>foxmp3 - %s - remote</title><link rel=\"stylesheet\" href=\"../local/stylesheet.css\" type=\"text/css\" /><script src=\"../local/json.js\" type=\"text/javascript\"></script></head><body onload=\"alpmp3_setup();\">"); + printf("<center><p id=alpmp3_remote>"); + printf("<table width=50%%>"); + printf("<tr class=cellhead><th colspan=3 id=cell align=center>FOXMP3 - %s </td></tr>", name); + printf("<tr class=cellone><td>Action</td><td colspan=2 id=alpmp3_state>0</td></tr>"); + printf("<tr class=celltwo><td>Filename</td><td colspan=2 id=alpmp3_filename>0</td></tr>"); + printf("<tr class=cellone><td>Playtime</td><td colspan=2 id=alpmp3_playtime>0</td></tr>"); + printf("<tr class=celltwo><td>Volume</td><td id=alpmp3_volume>0</td><td><a href=\"#\" onclick=\"javascript:alpmp3_remote('volup');\">Up</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('voldown')\">Down</a></td></tr>"); + printf("<tr class=cellone><td width=20%%>Bass</td><td id=alpmp3_bass>0</td><td><a href=\"#\" onclick=\"javascript:alpmp3_remote('bassup');\" class=browse>Up</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('bassdown')\" class=browse>Down</a></td></tr>"); + printf("<tr class=cellhead><th colspan=3 id=cell align=center><a href=\"#\" onclick=\"javascript:alpmp3_remote('start');\">Start</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('stop');\">Stop</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('back');\">Back</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('next');\">Next</a> </td></tr>"); + printf("</table>"); + printf("</p></center>"); + printf("</body></html>"); +} + + + +void print_json_info(){ + unsigned char str[2048]; + sprintf(str, "STATE"); + if(issue_command(str) == 0){ + int state = 0; + int volume = 0; + int bass = 0; + int playtime = 0; + unsigned char filename[1024]; + unsigned char *p1, *p2; + + memset(filename, 0, 1024); + p1 = str; + while(p1){ + p2 = strstr(p1, "\n"); + if(p2){ + *p2 = '\0'; + p2 ++; + // printf("parsing %s\n", p1); + if(strncmp(p1, "VOLUME", strlen("VOLUME")) == 0){ + volume = atoi(&p1[strlen("VOLUME") + 1]); + if(volume > 120) + volume = 120; + volume = 120 - volume; + volume /= 4; + //printf("vol = %d\n", volume); + } else if(strncmp(p1, "BASS", strlen("BASS")) == 0){ + bass = atoi(&p1[strlen("BASS") + 1]); + //printf("bass = %d\n", bass); + } else if(strncmp(p1, "PLAYTIME", strlen("PLAYTIME")) == 0){ + playtime = atoi(&p1[strlen("PLAYTIME") + 1]); + //printf("playtime = %d\n", playtime); + } else if(strncmp(p1, "STATE", strlen("STATE")) == 0){ + if(strstr(p1, "MP3_STATE_IDLE")){ + state = 0; + } else if(strstr(p1, "MP3_STATE_FILE")){ + state = 1; + } else if(strstr(p1, "MP3_STATE_STREAM")){ + state = 2; + } + //printf("state = %d\n", state); + } else if(strncmp(p1, "STREAM", strlen("STREAM")) == 0){ + strcpy(filename, &p1[strlen("STREAM") + 1]); + //printf("filename = %s\n", filename); + } else if(strncmp(p1, "FILE", strlen("FILE")) == 0){ + strcpy(filename, &p1[strlen("FILE") + 1]); + //printf("filename = %s\n", filename); + } + + p1 = p2; + } else { + p1 = 0; + } + } + + struct json_object *alpmp3 = json_object_new_object(); + json_object_object_add(alpmp3, "state", json_object_new_int(state)); + switch(state){ + case 1: + json_object_object_add(alpmp3, "type", json_object_new_string("file")); + break; + case 2: + json_object_object_add(alpmp3, "type", json_object_new_string("stream")); + break; + default: + json_object_object_add(alpmp3, "type", json_object_new_string("idle")); + break; + } + json_object_object_add(alpmp3, "volume", json_object_new_int(volume)); + json_object_object_add(alpmp3, "bass", json_object_new_int(bass)); + json_object_object_add(alpmp3, "playtime", json_object_new_int(playtime)); + json_object_object_add(alpmp3, "filename", json_object_new_string(filename)); + struct json_object *jo = json_object_new_object(); + json_object_object_add(jo, "alpmp3", alpmp3); + printf("\n%s\n", json_object_to_json_string(jo)); + } +} + +int main(int argc, char **argv){ + print_http_header(); + + if(strstr(argv[0], "mp3_remote.cgi")){ + print_html_remote(); + } else if(strstr(argv[0], "mp3_json.cgi")){ + print_json_info(); + } else if(strstr(argv[0], "mp3_cmd.cgi")){ + handle_cmd(); + } else { + printf("Unknown command"); + } + return 0; +} diff --git a/package/fonera-mp3/src/cgi/stylesheet.css b/package/fonera-mp3/src/cgi/stylesheet.css new file mode 100644 index 000000000..d58d47e24 --- /dev/null +++ b/package/fonera-mp3/src/cgi/stylesheet.css @@ -0,0 +1,31 @@ +body {
+ background-color:#FFFFFF;
+}
+
+font { font-family: Verdana, Arial, Helvetica, sans-serif }
+td { font-family: Arial, Helvetica, sans-serif; font-size: 12px }
+th { font-family: Arial, Helvetica, sans-serif }
+P { font-family: Arial, Helvetica, sans-serif }
+hr { height: 0px; border-top-width: 1px;}
+TH.surlink { font-family: Arial, Helvetica, sans-serif; color: #000000 }
+
+TH { background-color: #99CCCC; height: 0px; font-size: 11px; line-height : 100%; font-weight: bold; color: #000000 }
+TR.cellone { background-color: #FFFFCC; height: 16px; font-size: 12px; line-height : 100%; color: #000000 }
+TR.celltwo { background-color: #FFFF99; height: 16px; font-size: 12px; line-height : 100%; color: #000000 }
+TR.cellhead { background-color: #FFFF44; height: 16px; font-size: 12px; line-height : 100%; color: #000000 }
+
+.copyright { font-family: Verdana, Arial, Helvetica, sans-serif; color: #000000; font-size: 10px; letter-spacing: -1px;}
+.copyright a { color: #CC0000; text-decoration: none;}
+.copyright a:hover { color: #FF0000; text-decoration: underline;}
+
+.error_table { border-spacing:0px;border: 1px solid #000000;}
+.error_t {color:#000000;background-color:#FFFFDD;border-spacing:0px;border: 0px}
+
+a { color: #0000FF; text-decoration: underline;}
+a:hover { color: #FF0000; text-decoration: none;}
+.box {
+ background-color: #FFFFFF;
+ border: 1px solid #999900;
+ font-family: Verdana;
+ font-size: 10px;
+ }
diff --git a/package/fonera-mp3/src/cli/Makefile b/package/fonera-mp3/src/cli/Makefile new file mode 100644 index 000000000..e6aa0df92 --- /dev/null +++ b/package/fonera-mp3/src/cli/Makefile @@ -0,0 +1,26 @@ + +PROGS = mplay + +INSTDIR = $(prefix)/usr/bin +INSTMODE = 0755 +INSTOWNER = root +INSTGROUP = root + +OBJS = main.o + +all: $(PROGS) +$(PROGS): + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o mplay main.c + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o mplay_tcp main_tcp.c + gcc -o mplay_tcp_native main_tcp.c + $(STRIP) mplay + $(STRIP) mplay_tcp + +install: $(PROGS) + $(INSTALL) -d $(INSTDIR) + $(INSTALL) -m $(INSTMODE) -o $(INSTOWNER) -g $(INSTGROUP) $(PROGS) $(INSTDIR) + $(INSTALL) -m $(INSTMODE) -o $(INSTOWNER) -g $(INSTGROUP) $(PROGS)_tcp $(INSTDIR) + +clean: + rm -f $(PROGS) *.o core + diff --git a/package/fonera-mp3/src/cli/main.c b/package/fonera-mp3/src/cli/main.c new file mode 100644 index 000000000..abea0a61e --- /dev/null +++ b/package/fonera-mp3/src/cli/main.c @@ -0,0 +1,108 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +#define SOCKET_PATH "/tmp/foxmp3" + + +void print_usage(void){ + printf("mp3_play COMANND PARAMETERS\n"); + printf(" Commands :\n"); + printf(" PLAY filename\n"); + printf(" STREAM url [URL OF STREAM]\n"); + printf(" STREAM pls [URL PLS FILE]\n"); + printf(" VOLUME [0-255]\n"); + printf(" STOP\n"); + printf(" STATE\n"); + printf(" BASS [0-255]\n"); +} + +void issue_command(unsigned char *str){ + int s, t, len; + struct sockaddr_un remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + printf("Connecting to mp3d ...\n"); + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCKET_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + perror("connect"); + exit(1); + } + printf("Connected ...\n\nSending command -> \n%s\n\n", str); + if (send(s, str, strlen(str), 0) == -1) { + perror("send"); + exit(1); + } + unsigned char loop = 1; + while(loop){ + if ((t=recv(s, str, 2048, 0)) > 0) { + str[t] = '\0'; + printf("The answer was -> \n%s\n", str); + if((strstr(str, "OK")) || (strstr(str, "ERROR"))){ + loop = 0; + } + } else { + if (t < 0){ + perror("recv"); + } else { + printf("Server closed connection\n"); + }; + } + } + close(s); +} + +int main(int argc, char **argv){ + unsigned char buffer[2048]; + buffer[0] = '\0'; + if(argc > 1){ + if(((!strcmp(argv[1], "STOP")) || (!strcmp(argv[1], "STATE"))) + && (argc == 2)){ + sprintf(buffer, "%s", argv[1]); + } else if(((!strcmp(argv[1], "PLAY")) || (!strcmp(argv[1], "VOLUME")) + || (!strcmp(argv[1], "BASS"))) && (argc == 3)){ + sprintf(buffer, "%s %s", argv[1], argv[2]); + } else if((!strcmp(argv[1], "STREAM")) && (argc == 4) + && ((!strcmp(argv[2], "url")) || (!strcmp(argv[2], "pls")))){ + sprintf(buffer, "%s %s %s", argv[1], argv[2], + argv[3]); + } + }; + if(buffer[0] != '\0'){ + issue_command(buffer); + } else { + print_usage(); + }; + return 0; +} diff --git a/package/fonera-mp3/src/cli/main_tcp.c b/package/fonera-mp3/src/cli/main_tcp.c new file mode 100644 index 000000000..02fc41ea4 --- /dev/null +++ b/package/fonera-mp3/src/cli/main_tcp.c @@ -0,0 +1,118 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#define SOCKET_PORT 369 + + +void print_usage(void){ + printf("mp3_play_tcp IP COMANND PARAMETERS\n"); + printf(" Commands :\n"); + printf(" PLAY filename\n"); + printf(" STREAM url [URL OF STREAM]\n"); + printf(" STREAM pls [URL PLS FILE]\n"); + printf(" VOLUME [0-255]\n"); + printf(" STOP\n"); + printf(" STATE\n"); + printf(" BASS [0-255]\n"); +} + +void issue_command(unsigned char *str, unsigned char *ip){ + int s, t, len; + struct sockaddr_in remote; + struct hostent *he; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + + printf("Connecting to FOXMP3 on IP/DNS : %s ...\n", ip); + if((he=gethostbyname(ip)) == NULL) { + herror("gethostbyname"); + exit(1); + } + if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + remote.sin_family = AF_INET; + remote.sin_port = htons(SOCKET_PORT); + remote.sin_addr = *((struct in_addr *)he->h_addr); + memset(&(remote.sin_zero), '\0', 8); + + if (connect(s, (struct sockaddr *)&remote, + sizeof(struct sockaddr)) == -1) { + perror("connect"); + exit(1); + } + printf("Connected ...\n\nSending command -> \n%s\n\n", str); + if (send(s, str, strlen(str), 0) == -1) { + perror("send"); + exit(1); + } + if ((t=recv(s, str, 2048, 0)) > 0) { + str[t] = '\0'; + printf("The answer was -> \n%s\n", str); + } else { + if (t < 0){ + perror("recv"); + } else { + printf("Server closed connection\n"); + }; + exit(1); + } + close(s); +} + +int main(int argc, char **argv){ + unsigned char buffer[2048]; + buffer[0] = '\0'; + if(argc > 2){ + if(((!strcmp(argv[2], "STOP")) || (!strcmp(argv[2], "STATE"))) + && (argc == 3)){ + sprintf(buffer, "%s", argv[2]); + } else if(((!strcmp(argv[2], "PLAY")) || (!strcmp(argv[2], "VOLUME")) + || (!strcmp(argv[2], "BASS"))) && (argc == 4)){ + sprintf(buffer, "%s %s", argv[2], argv[3]); + } else if((!strcmp(argv[2], "STREAM")) && (argc == 5) + && ((!strcmp(argv[3], "url")) || (!strcmp(argv[3], "pls")))){ + sprintf(buffer, "%s %s %s", argv[2], argv[3], + argv[4]); + } + }; + if(buffer[0] != '\0'){ + issue_command(buffer, argv[1]); + } else { + print_usage(); + }; + return 0; +} diff --git a/package/fonera-mp3/src/lib/mp3.h b/package/fonera-mp3/src/lib/mp3.h new file mode 100644 index 000000000..77db813c9 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3.h @@ -0,0 +1,35 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include "mp3_file.h" +#include "mp3_stream.h" +#include "mp3_nix_socket.h" +#include "mp3_tcp_socket.h" +#include "mp3_common.h" +#include "mp3_statemachine.h" +#include "mp3_socket_parser.h" +#include "mp3_misc.h" +#include "mp3_playtime.h" +#include "mp3_states.h" + +void state_event(int event, EVENT_PARAM *param); +EVENT_PARAM* state_new_event(unsigned char *text, int numeric); diff --git a/package/fonera-mp3/src/lib/mp3_common.c b/package/fonera-mp3/src/lib/mp3_common.c new file mode 100644 index 000000000..3cdb0b8fc --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_common.c @@ -0,0 +1,121 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include "mp3.h" + +static int mp3_fd; +static int mp3_frequency_val = CRYSTAL12288; +unsigned int volume = 0x3030; + +int mp3_open_port(unsigned char *port_name){ + int fd; + if ((fd = open(port_name, O_RDWR)) < 0) { + printf("Error whilst opening %s\n", port_name); + return -1; + } + return fd; +}; + +void mp3_set_frequency(unsigned int crystal_frequency){ + mp3_frequency_val = crystal_frequency; +}; + +int mp3_init(void){ + mp3_fd = mp3_open_port("/dev/mp3"); + if(mp3_fd < 1){ + return 0; + }; + ioctl(mp3_fd, IOCTL_MP3_INIT, mp3_frequency_val); + return 1; +}; + +void mp3_shutdown(void){ + close(mp3_fd); +}; + +void mp3_bass(unsigned char t_freq, unsigned char t_amp, + unsigned char b_freq, unsigned char b_amp){ + unsigned int val; + if(t_amp > 0xf){ + t_amp = 0xf; + }; + if(b_amp > 0xf){ + b_amp = 0xf; + }; + val = t_amp; + val <<= 4; + val += t_freq; + val <<= 4; + val += b_amp; + val <<= 4; + val += b_freq; + ioctl(mp3_fd, IOCTL_MP3_BASS, val); +}; + +void mp3_reset(void){ + ioctl(mp3_fd, IOCTL_MP3_CLEARBUFFER, 0); + ioctl(mp3_fd, IOCTL_MP3_RESET, mp3_frequency_val); + ioctl(mp3_fd, IOCTL_MP3_SETVOLUME, volume); +}; + +unsigned char mp3_send_data_to_buffer(MP3_DATA mp3_data){ + return write(mp3_fd, (void*)&mp3_data, sizeof(MP3_DATA)); +}; + +unsigned char mp3_play(void){ + return ioctl(mp3_fd, IOCTL_MP3_PLAY, 0); +}; + +void mp3_stop(void){ + ioctl(mp3_fd, IOCTL_MP3_CLEARBUFFER, 0); +}; + +void mp3_beep(unsigned char freq, unsigned int ms){ + MP3_BEEP mp3_beep_; + mp3_beep_.freq = freq; + mp3_beep_.ms = ms; + ioctl(mp3_fd, IOCTL_MP3_BEEP, &mp3_beep_); +}; + +void mp3_set_volume(unsigned char left, unsigned char right){ + volume = left; + volume <<= 8; + volume += right; + + ioctl(mp3_fd, IOCTL_MP3_SETVOLUME, volume); +}; + +unsigned char mp3_buffer_finished(void){ + return ioctl(mp3_fd, IOCTL_MP3_END_REACHED, 0); +}; + +unsigned char mp3_get_audio_data(AUDIO_DATA *audio_data){ + return ioctl(mp3_fd, IOCTL_MP3_GETAUDIODATA, audio_data); +}; + + diff --git a/package/fonera-mp3/src/lib/mp3_common.h b/package/fonera-mp3/src/lib/mp3_common.h new file mode 100644 index 000000000..d1eb0fa56 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_common.h @@ -0,0 +1,72 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#define MP3_CHUNK_SIZE 4096 +#define MP3_BUFFERING 0 +#define MP3_PLAYING 1 +#define MP3_BUFFER_FINISHED 2 +#define MP3_PLAY_FINISHED 3 + +typedef struct _MP3_DATA{ + unsigned char mp3[MP3_CHUNK_SIZE]; + unsigned char state; +} MP3_DATA; + + +#define IOCTL_MP3_INIT 0x01 +#define IOCTL_MP3_RESET 0x02 +#define IOCTL_MP3_SETVOLUME 0x03 +#define IOCTL_MP3_GETVOLUME 0x04 +typedef struct _AUDIO_DATA{ + unsigned int bitrate; + unsigned int sample_rate; + unsigned char is_stereo; +}AUDIO_DATA; +#define IOCTL_MP3_GETAUDIODATA 0x05 + +#define IOCTL_MP3_CLEARBUFFER 0x06 +#define IOCTL_MP3_PLAY 0x07 +typedef struct _MP3_BEEP{ + unsigned char freq; + unsigned int ms; +} MP3_BEEP; +#define IOCTL_MP3_BEEP 0x08 +#define IOCTL_MP3_END_REACHED 0x09 + +#define IOCTL_MP3_BASS 0x10 + +#define CRYSTAL12288 0x9800 +#define CRYSTAL24576 0x0 + +#define MP3_OK 0 +#define MP3_ERROR 1 +#define MP3_END 2 + +void mp3_reset(void); +unsigned char mp3_send_data_to_buffer(MP3_DATA mp3_data); +unsigned char mp3_buffer_finished(void); +unsigned char mp3_play(void); +void mp3_stop(void); +int mp3_init(void); +void mp3_bass(unsigned char t_freq, unsigned char t_amp, + unsigned char b_freq, unsigned char b_amp); +void mp3_set_volume(unsigned char left, unsigned char right); diff --git a/package/fonera-mp3/src/lib/mp3_file.c b/package/fonera-mp3/src/lib/mp3_file.c new file mode 100644 index 000000000..2dbed0ffc --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_file.c @@ -0,0 +1,191 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> + +#include "mp3.h" + + +#define MP3_PRE_BUFFER_COUNT ((128 * 1024) / MP3_CHUNK_SIZE) + + +typedef struct _MP3_FILE { + unsigned char filename[2048]; + MP3_DATA mp3_data; + FILE *fd; + unsigned char file_end_found; + MP3_FILE_ID3 *id3; +} MP3_FILE; + +static MP3_FILE mp3_file; + +void mp3_load_id3(FILE *fp){ + unsigned char *buf = malloc(1024); + + mp3_file.id3->album[0] = '\0'; + mp3_file.id3->artist[0] = '\0'; + mp3_file.id3->track[0] = '\0'; + + + fgets(buf, 1024, fp); + if( (buf[0] == 'I') && + (buf[1] == 'D') && + (buf[2] == '3')){ + unsigned int id3_size; + unsigned int i; + unsigned int id3_version = buf[3]; + id3_version <<= 8; + id3_version += buf[4]; + + id3_size = 0; + + for(i = 0; i<4; i++){ + id3_size += buf[5 + i]; + id3_size <<= 7; + }; + if(id3_version>>8 == 3){ + unsigned int id3_pos = 10; + unsigned int id3_tag_size; + unsigned char tag_name[5]; + unsigned char tag_data[257]; + tag_name[4] = '\0'; + tag_data[256] = '\0'; + unsigned int count = 0; + while(count < 10){ + strncpy(tag_name, &buf[id3_pos], 4); + id3_tag_size = buf[id3_pos + 4]; + id3_tag_size <<= 8; + id3_tag_size = buf[id3_pos + 5]; + id3_tag_size <<= 8; + id3_tag_size = buf[id3_pos + 6]; + id3_tag_size <<= 8; + id3_tag_size = buf[id3_pos + 7]; + if(id3_tag_size == 0){ + break; + }; + if(id3_tag_size > 256){ + memcpy(&tag_data[0], &buf[id3_pos + 11] , 256); + } else { + memcpy(&tag_data[0], &buf[id3_pos + 11] , + id3_tag_size -1); + tag_data[id3_tag_size-1] = '\0'; + }; + id3_pos += 10 + id3_tag_size; + if(strcmp(tag_name, "TPE1") == 0){ + strncpy(mp3_file.id3->artist, tag_data, 255); + }; + if(strcmp(tag_name, "TALB") == 0){ + strncpy(mp3_file.id3->album, tag_data, 255); + }; + if(strcmp(tag_name, "TIT2") == 0){ + strncpy(mp3_file.id3->track, tag_data, 255); + }; + if(id3_pos >= id3_size){ + break; + }; + count ++; + }; + }; + printf("ID3 tag found Version 2.%d.%d / size %d\n%s -- %s -- %s\n", + id3_version>>8, + id3_version&0xff, + id3_size, + mp3_file.id3->artist, + mp3_file.id3->album, + mp3_file.id3->track); + } else { + printf("No ID3 Tag was found\n"); + }; + free(buf); +}; + + +int mp3_file_setup(unsigned char *filename, MP3_FILE_ID3 *id3){ + unsigned int i; + mp3_file.id3 = id3; + mp3_file.file_end_found = 0; + strcpy(mp3_file.filename, filename); + mp3_file.fd = fopen(mp3_file.filename, "rb"); + if(!mp3_file.fd){ + mp3_file.fd = 0; + printf("error opening file %s\n", mp3_file.filename); + return MP3_ERROR; + }; + printf("File %s opened Ok\n", mp3_file.filename); + printf("Reading id3 tag\n"); + mp3_load_id3(mp3_file.fd); + fseek(mp3_file.fd, 0, SEEK_SET); + + mp3_reset(); + + printf("Buffering MP3 Data\n"); + mp3_file.mp3_data.state = MP3_BUFFERING; + for(i = 0; i < MP3_PRE_BUFFER_COUNT - 1; i++){ + fread(mp3_file.mp3_data.mp3, MP3_CHUNK_SIZE, 1, mp3_file.fd); + mp3_file.mp3_data.state = MP3_PLAYING; + mp3_send_data_to_buffer(mp3_file.mp3_data); + }; + + printf("Starting to play file : %s\n", mp3_file.filename); + return MP3_OK; +}; + +int mp3_file_handle(void){ + unsigned char transmit_success = 1; + if (!feof(mp3_file.fd)) { + fread(mp3_file.mp3_data.mp3, MP3_CHUNK_SIZE, 1, mp3_file.fd); + transmit_success = 0; + while(!transmit_success){ + if(!mp3_send_data_to_buffer(mp3_file.mp3_data)){ + usleep(1); + transmit_success = 0; + } else { + transmit_success = 1; + }; + }; + return MP3_OK; + } else { + if(!mp3_file.file_end_found){ + mp3_file.mp3_data.state = MP3_BUFFER_FINISHED; + mp3_send_data_to_buffer(mp3_file.mp3_data); + printf("File end reached. Wait till kernel buffer has cleared.\n"); + mp3_file.file_end_found = 1; + }; + if(!mp3_buffer_finished()){ + return MP3_OK; + } else { + return MP3_END; + }; + }; +}; + +int mp3_file_cleanup(void){ + if(mp3_file.fd){ + fclose(mp3_file.fd); + }; + return MP3_OK; +}; diff --git a/package/fonera-mp3/src/lib/mp3_file.h b/package/fonera-mp3/src/lib/mp3_file.h new file mode 100644 index 000000000..1bff35209 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_file.h @@ -0,0 +1,31 @@ +/* +* a.lp_mp3 - Open Source Atmel AVR / Fox Board based MP3 Players +* Copyright (c) 2003-2006 K. John '2B|!2B' Crispin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs.... mail john{AT}phrozen.org +* +*/ + +typedef struct _MP3_FILE_ID3 { + unsigned char album[256]; + unsigned char artist[256]; + unsigned char track[256]; +} MP3_FILE_ID3; + +int mp3_file_setup(unsigned char *filename, MP3_FILE_ID3 *id3); +int mp3_file_handle(void); +int mp3_file_cleanup(void); diff --git a/package/fonera-mp3/src/lib/mp3_misc.c b/package/fonera-mp3/src/lib/mp3_misc.c new file mode 100644 index 000000000..9fba30fbb --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_misc.c @@ -0,0 +1,129 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "mp3.h" + +#define TMP_PLS_NAME "/var/tmp.pls" + +char* mp3_shell_run(char *filename, char **args, char *buffer, int length){ + int fd1[2], fd2[2], l; + if((pipe(fd1) !=0) || (pipe(fd2)!=0)){ + return NULL; + } + if (fork() == 0){ + close(fd1[1]); + close(fd2[0]); + if ((dup2(fd1[0], STDIN_FILENO) == -1) + || (dup2(fd2[1], STDOUT_FILENO) == -1)){ + exit(0); + } + close(fd1[0]); + close(fd2[1]); + execvp(filename, args); + printf("ERROR running : %s\n", filename); + exit(0); + } + memset(buffer,'\0',length); + close(fd1[0]); + close(fd2[1]); + close(fd1[1]); + wait(NULL); + if((l = read(fd2[0], buffer, length -1)) == -1){ + printf("read failed"); + return NULL; + } + buffer[l] = '\0'; + close (fd2[2]); + return buffer; +} + +int mp3_pls_get_info(unsigned char *pls_url, unsigned char *url, + unsigned char *path, unsigned int *port){ + int ret = MP3_ERROR; + char *exec_args[6]; + int i; + remove(TMP_PLS_NAME); + for (i = 0; i < 5; i++){ + exec_args[i] = malloc(2048); + } + exec_args[0][0] = '\0'; + strcpy(exec_args[1], "wget"); + strcpy(exec_args[2], pls_url); + strcpy(exec_args[3], "-O"); + strcpy(exec_args[4], TMP_PLS_NAME); + exec_args[5] = NULL; + printf("Getting pls file --> %s \n", exec_args[2]); + if(mp3_shell_run("wget", &exec_args[1], + exec_args[0], 2048)){ + struct stat s; + stat(TMP_PLS_NAME, &s); + if(s.st_size > 0){ + FILE *fp = fopen(TMP_PLS_NAME, "r"); + if(fp > 0){ + unsigned char *data = malloc(2048); + *url = '\0'; + while((!*url) && (!feof(fp))){ + if(fgets(data, 2048, fp) != NULL){ + if(strstr(data, "File")){ + unsigned char *t = strstr(data, "="); + if(t){ + t++; + if(mp3_stream_parse_url(t, url, + path, port) != MP3_OK){ + *url = '\0'; + } + } + } + } + } + fclose(fp); + free(data); + if(*url){ + ret = MP3_OK; + } + } + } + } else { + printf("WGET error\n"); + } + for (i = 0; i < 5; i++){ + free(exec_args[i]); + } + if(ret == MP3_OK){ + printf("Found file valid file in pls\n"); + } else { + printf("Error whilst parsing pls\n"); + } + return ret; +} + + + diff --git a/package/fonera-mp3/src/lib/mp3_misc.h b/package/fonera-mp3/src/lib/mp3_misc.h new file mode 100644 index 000000000..512192112 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_misc.h @@ -0,0 +1,26 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +char* mp3_shell_run(char *filename, char **args, char *buffer, int length); +int mp3_pls_get_info(unsigned char *pls_url, unsigned char *url, + unsigned char *path, unsigned int *port); diff --git a/package/fonera-mp3/src/lib/mp3_nix_socket.c b/package/fonera-mp3/src/lib/mp3_nix_socket.c new file mode 100644 index 000000000..964690d64 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_nix_socket.c @@ -0,0 +1,166 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <sys/socket.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/poll.h> +#include <stdarg.h> +#include <fcntl.h> +#include "mp3.h" + +#define SOCKET_PATH "/tmp/foxmp3" + +typedef struct _MP3_NIX_SOCKET { + fd_set master; + fd_set clients; + int max; + int listener; +} MP3_NIX_SOCKET; + +static MP3_NIX_SOCKET mp3_nix_socket; + +int mp3_nix_socket_setup(void){ + struct sockaddr_un myaddr; + int yes=1; + int len; + FD_ZERO(&mp3_nix_socket.master); + FD_ZERO(&mp3_nix_socket.clients); + + if ((mp3_nix_socket.listener = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + return MP3_ERROR; + } + if (setsockopt(mp3_nix_socket.listener, SOL_SOCKET, + SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror("setsockopt"); + return MP3_ERROR; + } + myaddr.sun_family = AF_UNIX; + strcpy(myaddr.sun_path, SOCKET_PATH); + unlink(myaddr.sun_path); + len = strlen(myaddr.sun_path) + sizeof(myaddr.sun_family); + if (bind(mp3_nix_socket.listener, (struct sockaddr *)&myaddr, len) == -1) { + perror("bind"); + return MP3_ERROR; + } + if (listen(mp3_nix_socket.listener, 3) == -1) { + perror("listen"); + return MP3_ERROR; + } + FD_SET(mp3_nix_socket.listener, &mp3_nix_socket.master); + mp3_nix_socket.max = mp3_nix_socket.listener; + + return MP3_OK; +}; + +int mp3_nix_socket_handle(void){ + struct sockaddr_un remoteaddr; + socklen_t addrlen; + int i; + int newfd; + char buf[1024]; + int nbytes; + char buf_out[1024]; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + mp3_nix_socket.clients = mp3_nix_socket.master; + + if (select(mp3_nix_socket.max + 1, &mp3_nix_socket.clients, + NULL, NULL, &tv) == -1) { + // sometimes the select is interrupted, because of the alarm signal used by the playtime counter + //perror("error whilst selecting socket"); + return MP3_ERROR; + } + for(i = 0; i <= mp3_nix_socket.max; i++) { + if (FD_ISSET(i, &mp3_nix_socket.clients)) { + if (i == mp3_nix_socket.listener) { + addrlen = sizeof(remoteaddr); + if ((newfd = accept(mp3_nix_socket.listener, + (struct sockaddr *)&remoteaddr, + &addrlen)) == -1) { + perror("error whilst accepting socket"); + return MP3_ERROR; + } else { + FD_SET(newfd, &mp3_nix_socket.master); + if (newfd > mp3_nix_socket.max) { + mp3_nix_socket.max = newfd; + } + fcntl(newfd, F_SETFL, O_NONBLOCK); + printf("New socket client on %d\n", newfd); + } + } else { + if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) { + if (nbytes == 0) { + printf("selectserver: socket hung up %d\n", i); + close(i); + FD_CLR(i, &mp3_nix_socket.master); + } else { + printf("error whilst receiving socket %d\n", i); + } + } else { + buf[nbytes] = '\0'; + printf("Got data : %s\n", buf); + mp3_parser_incoming(buf,buf_out); + if(*buf_out != '\0'){ + send(i, buf_out, strlen(buf_out), 0); + } + } + } + } + } + return MP3_OK; +} + +void mp3_nix_socket_write(unsigned char *data, ...){ + unsigned int i; + unsigned char t[2048]; + va_list ap; + + // clear possible dead sockets + mp3_nix_socket_handle(); + memset(t, 0, 2048); + va_start(ap, data); + vsprintf(t, data, ap); + va_end(ap); + printf("Sending data --> %s\n", t); + for(i = 0; i <= mp3_nix_socket.max; i++) { + if (FD_ISSET(i, &mp3_nix_socket.master)) { + if (i != mp3_nix_socket.listener) { + printf("Sending on socket %d\n", i); + send(i, t, strlen(t), 0); + } + } + } + printf("Finished sending\n"); +} + +int mp3_nix_socket_cleanup(void){ + return MP3_OK; +}; + diff --git a/package/fonera-mp3/src/lib/mp3_nix_socket.h b/package/fonera-mp3/src/lib/mp3_nix_socket.h new file mode 100644 index 000000000..d97f82ce6 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_nix_socket.h @@ -0,0 +1,25 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +int mp3_nix_socket_setup(void); +int mp3_nix_socket_handle(void); +int mp3_nix_socket_cleanup(void); +void mp3_nix_socket_write(unsigned char *data, ...); diff --git a/package/fonera-mp3/src/lib/mp3_playtime.c b/package/fonera-mp3/src/lib/mp3_playtime.c new file mode 100644 index 000000000..89325943f --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_playtime.c @@ -0,0 +1,61 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include "mp3.h" + + +static MP3_PLAYTIME *mp3_playtime; + +void sig_alarm_handler(int sig){ + alarm(1); + mp3_playtime->playtime++; + mp3_playtime->playtime_secs++; + if(mp3_playtime->playtime_secs > 59){ + mp3_playtime->playtime_mins++; + mp3_playtime->playtime_secs = 0; + } + state_generic_event(MP3_EVENT_GENERIC_PLAYTIME, 0, NULL); +}; + +void mp3_playtime_init(MP3_PLAYTIME *playtime){ + mp3_playtime = playtime; + signal(SIGALRM, sig_alarm_handler); +}; + +void mp3_playtime_start(void){ + mp3_playtime->playtime = 0; + mp3_playtime->playtime_secs = 0; + mp3_playtime->playtime_mins = 0; + alarm(1); + state_generic_event(MP3_EVENT_GENERIC_PLAYTIME, 0, NULL); +}; + +void mp3_playtime_stop(void){ + alarm(0); + mp3_playtime->playtime = 0; + mp3_playtime->playtime_secs = 0; + mp3_playtime->playtime_mins = 0; +}; diff --git a/package/fonera-mp3/src/lib/mp3_playtime.h b/package/fonera-mp3/src/lib/mp3_playtime.h new file mode 100644 index 000000000..618d1224f --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_playtime.h @@ -0,0 +1,33 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +typedef struct _MP3_PLAYTIME { + unsigned int playtime; + unsigned int playtime_secs; + unsigned int playtime_mins; +} MP3_PLAYTIME; + +void mp3_playtime_init(MP3_PLAYTIME *playtime); +void mp3_playtime_start(void); +void mp3_playtime_stop(void); + diff --git a/package/fonera-mp3/src/lib/mp3_socket_parser.c b/package/fonera-mp3/src/lib/mp3_socket_parser.c new file mode 100644 index 000000000..1702282e8 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_socket_parser.c @@ -0,0 +1,104 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "mp3.h" + +#define TOKEN_MAX 16 +#define TOKEN_SIZE 256 + +static unsigned char mp3_parser_tokens[TOKEN_MAX][TOKEN_SIZE]; + +int mp3_parser_tokenize(unsigned char *in){ + int i = 0; + char *token = in; + char *tmp; + do { + tmp = strstr(token, " "); + if(tmp){ + *tmp = '\0'; + strcpy(mp3_parser_tokens[i], token); + tmp++; + token = tmp; + } else { + strcpy(mp3_parser_tokens[i], token); + }; + i++; + }while((i < TOKEN_MAX) && (tmp)); + return i; +}; + +extern int state_current; +void mp3_parser_incoming(unsigned char *in, unsigned char *out){ + int c = mp3_parser_tokenize(in); + int ret = 0; + int t1; + if(c){ + printf("Parsing command from frontend app -> %s --- %d tokens\n", in, c); + if((!strcmp(mp3_parser_tokens[0], "PLAY")) && (c == 2)){ + state_event(MP3_EVENT_FILE, state_new_event(mp3_parser_tokens[1], 0)); + ret = 1; + } else if((!strcmp(mp3_parser_tokens[0], "STREAM")) + && (c == 3)){ + if(!strcmp(mp3_parser_tokens[1], "pls")){ + state_event(MP3_EVENT_STREAM, state_new_event(mp3_parser_tokens[2], STREAM_PLS)); + ret = 1; + } else if(!strcmp(mp3_parser_tokens[1], "url")){ + state_event(MP3_EVENT_STREAM, state_new_event(mp3_parser_tokens[2], STREAM_URL)); + ret = 1; + } + } else if((!strcmp(mp3_parser_tokens[0], "VOLUME")) + && (c == 2)){ + t1 = atoi(mp3_parser_tokens[1]); + state_generic_event(MP3_EVENT_GENERIC_VOLUME, t1, NULL); + ret = 1; + } else if((!strcmp(mp3_parser_tokens[0], "STOP")) + && (c == 1)){ + state_event(MP3_EVENT_STOP, NULL); + ret = 1; + } else if((!strcmp(mp3_parser_tokens[0], "STATE")) + && (c == 1)){ + state_generic_event(MP3_EVENT_GENERIC_STATE, 0, out); + return; + } else if((!strcmp(mp3_parser_tokens[0], "BASS")) + && (c == 2)){ + t1 = atoi(mp3_parser_tokens[1]); + state_generic_event(MP3_EVENT_GENERIC_BASS, t1, NULL); + ret = 1; + } + if(ret){ + sprintf(out, "OK\n"); + printf("Command parsed ok.\n"); + } else { + + sprintf(out, "ERROR\n"); + printf("Command parsed with error.\n"); + }; + } else { + printf("Got command from frontend with 0 tokens.\n"); + }; +}; + + diff --git a/package/fonera-mp3/src/lib/mp3_socket_parser.h b/package/fonera-mp3/src/lib/mp3_socket_parser.h new file mode 100644 index 000000000..ebb517939 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_socket_parser.h @@ -0,0 +1,24 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +void mp3_parser_incoming(unsigned char *in, unsigned char *out); + diff --git a/package/fonera-mp3/src/lib/mp3_statemachine.h b/package/fonera-mp3/src/lib/mp3_statemachine.h new file mode 100644 index 000000000..072bb380c --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_statemachine.h @@ -0,0 +1,26 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +void mp3_init_statemachine(); +void mp3_statemachine_main_loop(); + diff --git a/package/fonera-mp3/src/lib/mp3_states.c b/package/fonera-mp3/src/lib/mp3_states.c new file mode 100644 index 000000000..f6f03eb87 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_states.c @@ -0,0 +1,224 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/poll.h> +#include <signal.h> +#include "mp3.h" + +typedef struct _MP3_STATE { + struct { + unsigned char volume; + unsigned char bass; + unsigned char treble; + } decoder; + struct { + unsigned char name[2048]; + MP3_FILE_ID3 id3; + } file; + struct { + unsigned char url[2048]; + unsigned char path[256]; + unsigned int port; + } stream; + MP3_PLAYTIME playtime; + } MP3_STATE; + +static MP3_STATE mp3_state; + +void state_startup_enter(int state_last, int event, EVENT_PARAM *param){ + mp3_state.decoder.volume = 0x30; + mp3_state.decoder.bass = 1; + mp3_state.file.name[0] = '\0'; + mp3_state.stream.url[0] = '\0'; + mp3_state.stream.path[0] = '\0'; + mp3_state.stream.port = 0; + mp3_playtime_init(&mp3_state.playtime); + mp3_init(); + mp3_nix_socket_setup(); + mp3_tcp_socket_setup(); +}; + +void state_idle_enter(int state_last, int event, EVENT_PARAM *param){ + mp3_stop(); + mp3_playtime_stop(); +}; + +void state_file_startup_enter(int state_last, int event, EVENT_PARAM *param){ + if(mp3_file_setup(param->text, &mp3_state.file.id3) == MP3_OK){ + strcpy(mp3_state.file.name, param->text); + } else { + state_event(MP3_EVENT_ERROR, NULL); + }; +}; + +void state_file_startup_leave(int state_new, int event){ + if(state_new == MP3_STATE_FILE_HANDLE){ + mp3_play(); + mp3_playtime_start(); + mp3_nix_socket_write("START FILE\n"); + }; +}; + +void state_file_handle_enter(int state_last, int event, EVENT_PARAM *param){ + int ret = mp3_file_handle(); + if(ret == MP3_ERROR){ + state_event(MP3_EVENT_ERROR, NULL); + }; + if(ret == MP3_END){ + state_event(MP3_EVENT_END, NULL); + }; + +}; + +void state_file_handle_leave(int state_new, int event){ + if(state_new != MP3_STATE_FILE_HANDLE){ + mp3_playtime_stop(); + mp3_file_cleanup(); + mp3_nix_socket_write("STOP FILE\n"); + }; +}; + +void state_stream_startup_enter(int state_last, int event, EVENT_PARAM *param){ + if(mp3_stream_setup(param->text, param->numeric, mp3_state.stream.url, + mp3_state.stream.path, &mp3_state.stream.port) != MP3_OK){ + state_event(MP3_EVENT_ERROR, NULL); + }; +}; + +void state_stream_startup_leave(int state_new, int event){ + if(state_new == MP3_STATE_STREAM_HANDLE){ + mp3_play(); + mp3_playtime_start(); + mp3_nix_socket_write("START STREAM\n"); + }; +}; + +void state_stream_handle_enter(int state_last, int event, EVENT_PARAM *param){ + if(mp3_stream_handle() == MP3_ERROR){ + state_event(MP3_EVENT_ERROR, NULL); + } +}; + +void state_stream_handle_leave(int state_new, int event){ + if(state_new != MP3_STATE_STREAM_HANDLE){ + mp3_stream_cleanup(); + mp3_playtime_stop(); + mp3_nix_socket_write("STOP STREAM\n"); + } +}; + +extern STATE states[MAX_STATE_COUNT]; +void state_error_enter(int state_last, int event, EVENT_PARAM *param){ + if(param){ + printf("Error in state %s -> %s\n", states[state_last].name, param->text); + mp3_nix_socket_write("ERROR Error in state %s -> %s\n", states[state_last].name, param->text); + } else { + printf("Unknown error in state %s\n", states[state_last].name); + }; +}; + +void state_shutdown_enter(int state_last, int event, EVENT_PARAM *param){ + printf("Entering state SHUTDOWN ...\n"); + printf("Shutting down player ...\n"); + mp3_nix_socket_cleanup(); + mp3_tcp_socket_cleanup(); + printf("Quitting statemachine ...\n"); + exit(0); +}; +extern int state_current; +void state_generic_event(unsigned int event, unsigned char in_int, + unsigned char *out_uchar){ + switch(event){ + case MP3_EVENT_GENERIC_VOLUME: + mp3_state.decoder.volume = in_int; + mp3_set_volume(mp3_state.decoder.volume, + mp3_state.decoder.volume); + mp3_nix_socket_write("VOLUME %d\n", mp3_state.decoder.volume); + break; + case MP3_EVENT_GENERIC_BASS: + mp3_state.decoder.bass = in_int; + mp3_bass(8, mp3_state.decoder.treble, + 8, mp3_state.decoder.bass); + mp3_nix_socket_write("BASS %d\n", mp3_state.decoder.bass); + break; + case MP3_EVENT_GENERIC_STATE: + out_uchar[0] = '\0'; + sprintf(out_uchar, "%sVOLUME %d\n", + out_uchar, mp3_state.decoder.volume); + sprintf(out_uchar, "%sBASS %d\n", + out_uchar, mp3_state.decoder.bass); + sprintf(out_uchar, "%sTREBLE %d\n", + out_uchar, mp3_state.decoder.treble); + sprintf(out_uchar, "%sPLAYTIME %d\n", + out_uchar, + (mp3_state.playtime.playtime_mins * 60) + mp3_state.playtime.playtime_secs); + switch(state_current){ + case MP3_STATE_IDLE: + sprintf(out_uchar, "%sSTATE MP3_STATE_IDLE\n", out_uchar); + break; + case MP3_STATE_FILE_START: + case MP3_STATE_FILE_HANDLE: + sprintf(out_uchar, "%sFILE %s\n", out_uchar, + mp3_state.file.name); + if(strlen(mp3_state.file.id3.artist)){ + sprintf(out_uchar, "%sID3_ARTIST %s\n", + out_uchar, + mp3_state.file.id3.artist); + }; + if(strlen(mp3_state.file.id3.album)){ + sprintf(out_uchar, "%sID3_ALBUM %s\n", + out_uchar, + mp3_state.file.id3.album); + }; + if(strlen(mp3_state.file.id3.album)){ + sprintf(out_uchar, "%sID3_TRACK %s\n", + out_uchar, + mp3_state.file.id3.track); + }; + sprintf(out_uchar, "%sSTATE MP3_STATE_FILE\n", out_uchar); + break; + case MP3_STATE_STREAM_START: + case MP3_STATE_STREAM_HANDLE: + sprintf(out_uchar, "%sSTREAM %s:%d%s\n", out_uchar, + mp3_state.stream.url, + mp3_state.stream.port, + mp3_state.stream.path); + sprintf(out_uchar, "%sSTATE MP3_STATE_STREAM\n", out_uchar); + break; + default: + sprintf(out_uchar, "STATE Unkonwn\n"); + break; + }; + sprintf(out_uchar, "%sOK\n", out_uchar); + break; + case MP3_EVENT_GENERIC_PLAYTIME: + // printf("%02d:%02d\n", mp3_state.playtime.playtime_mins, + // mp3_state.playtime.playtime_secs); + break; + default: + break; + }; +}; + diff --git a/package/fonera-mp3/src/lib/mp3_states.h b/package/fonera-mp3/src/lib/mp3_states.h new file mode 100644 index 000000000..073c28bb1 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_states.h @@ -0,0 +1,114 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +typedef struct _EVENT { + unsigned char *name; +} EVENT; + +typedef struct _EVENT_PARAM { + int numeric; + unsigned char *text; +} EVENT_PARAM; + +typedef void (*STATE_ENTER)(int state_last, int event, EVENT_PARAM *param); +typedef void (*STATE_LEAVE)(int state_new, int event); + +typedef struct _STATE { + unsigned char *name; + STATE_ENTER enter; + STATE_LEAVE leave; +} STATE; + +typedef struct _TRANSITION { + int old_state; + int event; + int new_state; +} TRANSITION; + +// a = id, b = name, c = enter, d = leave +#define STATE_ADD(a, b, c, d) { \ + if((a > 0) && (a < MAX_STATE_COUNT)){ \ + states[a].name = strdup(b); \ + states[a].enter = c; \ + states[a].leave = d; \ + } \ + } + +// a = old, b = event, c = new +#define TRANSITION_ADD(a, b, c) { \ + if((transition_count >= 0) && \ + (transition_count < MAX_TRANSITION_COUNT)){ \ + transitions[transition_count].old_state = a; \ + transitions[transition_count].event = b; \ + transitions[transition_count].new_state = c; \ + transition_count++; \ + } \ + } + +// a = id, b = name +#define EVENT_ADD(a, b) { \ + if((a > 0) && (a < MAX_EVENT_COUNT)){ \ + events[a].name = strdup(b); \ + } \ + } +#define MAX_EVENT_COUNT 20 +#define MAX_STATE_COUNT 20 +#define MAX_TRANSITION_COUNT 60 + +#define MP3_STATE_NONE 0 +#define MP3_STATE_STARTUP 1 +#define MP3_STATE_IDLE 2 +#define MP3_STATE_FILE_START 3 +#define MP3_STATE_FILE_HANDLE 4 +#define MP3_STATE_STREAM_START 5 +#define MP3_STATE_STREAM_HANDLE 6 +#define MP3_STATE_ERROR 7 +#define MP3_STATE_SHUTDOWN 8 +#define MP3_STATE_DEFAULT 9 + +#define MP3_EVENT_TIMEOUT 1 +#define MP3_EVENT_FILE 2 +#define MP3_EVENT_STREAM 3 +#define MP3_EVENT_STOP 4 +#define MP3_EVENT_ERROR 5 +#define MP3_EVENT_SHUTDOWN 6 +#define MP3_EVENT_END 7 + +#define MP3_EVENT_GENERIC_VOLUME 0 +#define MP3_EVENT_GENERIC_STATE 1 +#define MP3_EVENT_GENERIC_BASS 2 +#define MP3_EVENT_GENERIC_PLAYTIME 3 + +void state_startup_enter(int state_last, int event, EVENT_PARAM *param); +void state_idle_enter(int state_last, int event, EVENT_PARAM *param); +void state_file_startup_enter(int state_last, int event, EVENT_PARAM *param); +void state_file_startup_leave(int state_new, int event); +void state_file_handle_enter(int state_last, int event, EVENT_PARAM *param); +void state_file_handle_leave(int state_new, int event); +void state_stream_startup_enter(int state_last, int event, EVENT_PARAM *param); +void state_stream_startup_leave(int state_last, int event); +void state_stream_handle_enter(int state_last, int event, EVENT_PARAM *param); +void state_stream_handle_leave(int state_new, int event); +void state_error_enter(int state_last, int event, EVENT_PARAM *param); +void state_shutdown_enter(int state_last, int event, EVENT_PARAM *param); +void state_generic_event(unsigned int event, unsigned char in_int, + unsigned char *out_uchar); diff --git a/package/fonera-mp3/src/lib/mp3_stream.c b/package/fonera-mp3/src/lib/mp3_stream.c new file mode 100644 index 000000000..0dd3437e3 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_stream.c @@ -0,0 +1,340 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/time.h> +#include <sys/poll.h> + +#include "mp3.h" + +typedef struct _MP3_STREAM { + unsigned char buf[MAX_PACKET_SIZE + 1]; + int sockfd; + unsigned char mp3_buffer[MAX_BUFFER_SIZE]; + unsigned long int mp3_buffer_write_pos; + unsigned long int mp3_buffer_read_pos; + unsigned long int mp3_data_in_buffer; + unsigned char transmit_success; + unsigned int buffer_error; + MP3_DATA mp3_data; + unsigned int numbytes; + unsigned int metainterval; +} MP3_STREAM; + +static MP3_STREAM mp3_stream; + +int connect_timeout (int sfd, struct sockaddr *addr, int addrlen, + struct timeval *timeout) { + struct timeval sv; + int svlen = sizeof sv; + int ret; + + if (!timeout) { + return connect (sfd, addr, addrlen); + }; + if (getsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&sv, &svlen) < 0) { + return -1; + }; + if (setsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, timeout,sizeof *timeout) < 0) { + return -1; + }; + ret = connect (sfd, addr, addrlen); + setsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&sv, sizeof sv); + + return ret; +} + +int mp3_stream_parse_url(unsigned char *url, unsigned char *ip, + unsigned char *path, unsigned int *port){ + int len = strlen(url) - 1; + while(((url[len] == '\n')||(url[len] == ' ')) && (len > 0)){ + url[len] = '\0'; + len--; + }; + ip[0] = '\0'; + printf("Parsing stream url : %s\n", url); + unsigned char *http = strstr(url, "http://"); + *port = 80; + if(http){ + url = http + 7; + unsigned char *p = strstr(url, ":"); + if(p){ + *p = '\0'; + p ++; + strcpy(ip, url); + *port = atoi(p); + } + unsigned char *p2 = strstr((p)?(p):(url), "/"); + if(p2){ + strcpy(path, p2); + *p2 = '\0'; + if(!p){ + strcpy(ip, url); + } + + } else { + strcpy(path, "/"); + }; + printf("ip -> %s\nport -> %d\npath -> %s\n", ip, *port, path); + return MP3_OK; + }; + return MP3_ERROR; +}; + +int mp3_stream_get_url(unsigned char *url, unsigned int type, + unsigned char *ip, unsigned int *port, unsigned char *path){ + if(type == STREAM_PLS){ + if(mp3_pls_get_info(url, ip, path, port) == MP3_OK){ + return MP3_OK; + }; + } else if(type == STREAM_URL){ + if(mp3_stream_parse_url(url, ip, path, port) == MP3_OK){ + return MP3_OK; + }; + }; + return MP3_ERROR; +}; + +int mp3_stream_setup(unsigned char *url, unsigned int type, unsigned char *ip, + unsigned char *path, unsigned int *port){ + struct hostent *he; + struct sockaddr_in their_addr; + unsigned int error = 0; + if(mp3_stream_get_url(url, type, ip, port, path) == MP3_ERROR){ + return MP3_ERROR; + }; + + mp3_stream.mp3_buffer_write_pos = 0; + mp3_stream.mp3_buffer_read_pos = 0; + mp3_stream.mp3_data_in_buffer = 0; + mp3_stream.transmit_success = 1; + mp3_stream.buffer_error = 0; + mp3_stream.metainterval = 0; + + mp3_reset(); + + if ((he=gethostbyname(ip)) == NULL) { + perror("Error in gethostbyname. Wrong url/ip ?"); + return MP3_ERROR; + } + if ((mp3_stream.sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("Error opening stream socket"); + return MP3_ERROR; + } + + their_addr.sin_family = AF_INET; + their_addr.sin_port = htons(*port); + their_addr.sin_addr = *((struct in_addr *)he->h_addr); + memset(&(their_addr.sin_zero), '\0', 8); + + struct timeval tv; + tv.tv_sec = 4; + tv.tv_usec = 0; + + if (connect_timeout(mp3_stream.sockfd, (struct sockaddr *)&their_addr, + sizeof(struct sockaddr), &tv) == -1) { + perror("connect"); + return MP3_ERROR; + } + + unsigned char icy_request[1024]; + sprintf(icy_request, + "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: A.LP-MP3\r\nAccept: */*\r\nicy-metadata:0\r\n\r\n", + path, + ip); + printf("Sending request :\n%s\n", icy_request); + send(mp3_stream.sockfd, icy_request, strlen(icy_request), 0); + //wait 200 ms ??!? some icecast servers seem to not push data to us fast enough ?!?!? + poll(0,0,200); + if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf, MAX_PACKET_SIZE-1, 0)) == -1) { + perror("recv"); + return MP3_ERROR; + } + mp3_stream.buf[mp3_stream.numbytes] = '\0'; + printf("numbytes = %d\n", mp3_stream.numbytes); + printf("------\n%s\n---------\n", mp3_stream.buf); + unsigned char *p = strstr(mp3_stream.buf, "\r\n\r\n"); + if(p) { + *p = '\0'; + p += 4; + } else { + printf("funky p error in stream.c\n"); + } + printf("Received: \n%s\n", mp3_stream.buf); + if(((unsigned char*)strstr(mp3_stream.buf, "ICY 200 OK") != mp3_stream.buf) && + ((unsigned char*)strstr(mp3_stream.buf, "HTTP/1.1 200 OK") != mp3_stream.buf) && + ((unsigned char*)strstr(mp3_stream.buf, "HTTP/1.0 200 OK") != mp3_stream.buf)) { + return MP3_ERROR; + }; + int p_buf = p - mp3_stream.buf; + unsigned char *p2; + p2 = strstr(mp3_stream.buf, "icy-metaint:"); + if(p2){ + p2 = strstr(p2, ":"); + p2++; + unsigned char *p3 = strstr(p2, "\r"); + *p3 = '\0'; + mp3_stream.metainterval = atoi(p2); + printf("META INT == %d\n", mp3_stream.metainterval); + } + + printf("starting to buffer\n"); + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + p, p_buf); + mp3_stream.mp3_buffer_write_pos += p_buf; + mp3_stream.mp3_data_in_buffer += p_buf; + + while(mp3_stream.mp3_data_in_buffer + (unsigned long int)MAX_PACKET_SIZE + < (unsigned long int)MAX_BUFFER_SIZE){ + if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf, + MAX_PACKET_SIZE-1, 0)) == -1) { + perror("disconnected"); + printf("disconntected\n"); + return MP3_ERROR; + } + + if(mp3_stream.numbytes == 0){ + sleep(1); + if(++error > 3){ + perror("disconnected"); + printf("disconntected\n"); + return MP3_ERROR; + } + } + + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + mp3_stream.buf, mp3_stream.numbytes); + mp3_stream.mp3_buffer_write_pos += mp3_stream.numbytes; + mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes; + printf("%ld ", mp3_stream.mp3_data_in_buffer); + fflush(stdout); + + }; + printf("\n"); + mp3_stream.mp3_data.state = MP3_PLAYING; + while(mp3_stream.mp3_data_in_buffer >= 2 * MP3_CHUNK_SIZE){ + memcpy(mp3_stream.mp3_data.mp3, + &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos], + MP3_CHUNK_SIZE); + mp3_send_data_to_buffer(mp3_stream.mp3_data); + mp3_stream.mp3_buffer_read_pos += MP3_CHUNK_SIZE; + mp3_stream.mp3_data_in_buffer -= MP3_CHUNK_SIZE; + }; + + printf("Starting to play stream\n"); + return MP3_OK; +} + +static int max_recv_errors = 10; +int mp3_stream_handle(void){ + if(MAX_BUFFER_SIZE >= mp3_stream.mp3_data_in_buffer + MAX_PACKET_SIZE){ + struct pollfd ufds; + ufds.fd = mp3_stream.sockfd; + ufds.events = POLLIN|POLLHUP; + + if(poll(&ufds, 1, 2000) > 0){ + max_recv_errors = 10; + if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf, MAX_PACKET_SIZE-1, 0)) == -1) { + perror("recv"); + } + if((mp3_stream.numbytes != EAGAIN)&& (mp3_stream.numbytes != -1)){ + if(mp3_stream.mp3_buffer_write_pos + mp3_stream.numbytes <= MAX_BUFFER_SIZE){ + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + mp3_stream.buf, mp3_stream.numbytes); + mp3_stream.mp3_buffer_write_pos += mp3_stream.numbytes; + mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes; + if(mp3_stream.mp3_buffer_write_pos == MAX_BUFFER_SIZE){ + mp3_stream.mp3_buffer_write_pos = 0; + }; + } else { + unsigned int buffer_offset = MAX_BUFFER_SIZE - mp3_stream.mp3_buffer_write_pos; + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + mp3_stream.buf, buffer_offset); + mp3_stream.mp3_buffer_write_pos = + mp3_stream.numbytes - buffer_offset; + memcpy(&mp3_stream.mp3_buffer[0], &mp3_stream.buf[buffer_offset], + mp3_stream.mp3_buffer_write_pos); + mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes; + }; + }; + } else { + max_recv_errors--; + if(max_recv_errors == 0){ + printf("recv error\n"); + return MP3_ERROR; + }; + }; + } + + if(mp3_stream.mp3_data_in_buffer < MP3_CHUNK_SIZE){ + printf("radio_buffer is empty\n"); + mp3_stream.buffer_error ++; + if(mp3_stream.buffer_error > MAX_BUFFER_ERROR){ + return MP3_ERROR; + }; + } else { + mp3_stream.buffer_error = 0; + do{ + if(mp3_stream.transmit_success){ + if(MAX_BUFFER_SIZE >= mp3_stream.mp3_buffer_read_pos + MP3_CHUNK_SIZE){ + memcpy(mp3_stream.mp3_data.mp3, + &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos], MP3_CHUNK_SIZE); + mp3_stream.mp3_buffer_read_pos += MP3_CHUNK_SIZE; + mp3_stream.mp3_data_in_buffer -= MP3_CHUNK_SIZE; + if(mp3_stream.mp3_buffer_read_pos == MAX_BUFFER_SIZE){ + mp3_stream.mp3_buffer_read_pos = 0; + }; + + } else { + unsigned int buffer_offset = MAX_BUFFER_SIZE - mp3_stream.mp3_buffer_read_pos; + memcpy(mp3_stream.mp3_data.mp3, + &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos], + buffer_offset); + mp3_stream.mp3_buffer_read_pos = MP3_CHUNK_SIZE - buffer_offset; + memcpy(&mp3_stream.mp3_data.mp3[buffer_offset], mp3_stream.mp3_buffer, + mp3_stream.mp3_buffer_read_pos); + }; + } + if(!mp3_send_data_to_buffer(mp3_stream.mp3_data)){ + mp3_stream.transmit_success = 0; + } else { + mp3_stream.transmit_success = 1; + }; + } while((mp3_stream.transmit_success)&&(mp3_stream.mp3_data_in_buffer > MP3_CHUNK_SIZE)); + }; + return MP3_OK; +}; + +int mp3_stream_cleanup(void){ + close(mp3_stream.sockfd); + return MP3_OK; +} diff --git a/package/fonera-mp3/src/lib/mp3_stream.h b/package/fonera-mp3/src/lib/mp3_stream.h new file mode 100644 index 000000000..d8e09ba5e --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_stream.h @@ -0,0 +1,34 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#define MAX_PACKET_SIZE 1500 +#define MAX_BUFFER_SIZE (64*2048) +#define MAX_BUFFER_ERROR 128 + +#define STREAM_URL 0 +#define STREAM_PLS 1 +int mp3_stream_setup(unsigned char *url, unsigned int type, unsigned char *ip, + unsigned char *path, unsigned int *port); +int mp3_stream_handle(void); +int mp3_stream_cleanup(void); +int mp3_stream_parse_url(unsigned char *url, unsigned char *ip, + unsigned char *path, unsigned int *port); diff --git a/package/fonera-mp3/src/lib/mp3_tcp_socket.c b/package/fonera-mp3/src/lib/mp3_tcp_socket.c new file mode 100644 index 000000000..89c8997fe --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_tcp_socket.c @@ -0,0 +1,145 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/wait.h> +#include <signal.h> +#include <sys/poll.h> + +#include "mp3.h" + +#define SOCKET_PORT 369 +#define BACKLOG 10 + +typedef struct _MP3_TCP_SOCKET { + fd_set master; + fd_set clients; + int max; + int listener; +} MP3_TCP_SOCKET; + +static MP3_TCP_SOCKET mp3_tcp_socket; + +int mp3_tcp_socket_setup(void){ + struct sockaddr_in myaddr; + int yes=1; + FD_ZERO(&mp3_tcp_socket.master); + FD_ZERO(&mp3_tcp_socket.clients); + + if ((mp3_tcp_socket.listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket"); + return MP3_ERROR; + } + if (setsockopt(mp3_tcp_socket.listener, SOL_SOCKET, + SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror("setsockopt"); + return MP3_ERROR; + } + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(SOCKET_PORT); + myaddr.sin_addr.s_addr = INADDR_ANY; + memset(&(myaddr.sin_zero), '\0', 8); + if (bind(mp3_tcp_socket.listener, (struct sockaddr *)&myaddr, sizeof(struct sockaddr)) == -1) { + perror("bind"); + return MP3_ERROR; + } + if (listen(mp3_tcp_socket.listener, 3) == -1) { + perror("listen"); + return MP3_ERROR; + } + FD_SET(mp3_tcp_socket.listener, &mp3_tcp_socket.master); + mp3_tcp_socket.max = mp3_tcp_socket.listener; + printf("Started tcp socket on port %d\n", SOCKET_PORT); + return MP3_OK; +}; + +int mp3_tcp_socket_handle(void){ + struct sockaddr_in remoteaddr; + socklen_t addrlen; + int i; + int newfd; + char buf[1024]; + int nbytes; + char buf_out[1024]; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + mp3_tcp_socket.clients = mp3_tcp_socket.master; + + if (select(mp3_tcp_socket.max + 1, &mp3_tcp_socket.clients, + NULL, NULL, &tv) == -1) { + return MP3_ERROR; + } + for(i = 0; i <= mp3_tcp_socket.max; i++) { + if (FD_ISSET(i, &mp3_tcp_socket.clients)) { + if (i == mp3_tcp_socket.listener) { + addrlen = sizeof(remoteaddr); + if ((newfd = accept(mp3_tcp_socket.listener, + (struct sockaddr *)&remoteaddr, + &addrlen)) == -1) { + perror("error whilst accepting socket"); + return MP3_ERROR; + } else { + printf("New TCP connection from %s\n", + inet_ntoa(remoteaddr.sin_addr)); + FD_SET(newfd, &mp3_tcp_socket.master); + if (newfd > mp3_tcp_socket.max) { + mp3_tcp_socket.max = newfd; + } + } + } else { + if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) { + if (nbytes == 0) { + perror("selectserver: socket hung up\n"); + } else { + perror("error whilst receiving socket"); + } + close(i); + FD_CLR(i, &mp3_tcp_socket.master); + } else { + buf[nbytes] = '\0'; + printf("Got data : %s\n", buf); + mp3_parser_incoming(buf,buf_out); + if(*buf_out != '\0'){ + send(i, buf_out, strlen(buf_out), 0); + } + close(i); + FD_CLR(i, &mp3_tcp_socket.master); + } + } + } + } + return MP3_OK; +}; + +int mp3_tcp_socket_cleanup(void){ + return MP3_OK; +}; + diff --git a/package/fonera-mp3/src/lib/mp3_tcp_socket.h b/package/fonera-mp3/src/lib/mp3_tcp_socket.h new file mode 100644 index 000000000..f4b5dc422 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_tcp_socket.h @@ -0,0 +1,24 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +int mp3_tcp_socket_setup(void); +int mp3_tcp_socket_handle(void); +int mp3_tcp_socket_cleanup(void); diff --git a/package/fonera-mp3/src/mp3_main.c b/package/fonera-mp3/src/mp3_main.c new file mode 100644 index 000000000..f1f21d677 --- /dev/null +++ b/package/fonera-mp3/src/mp3_main.c @@ -0,0 +1,204 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/poll.h> +#include <signal.h> +#include "lib/mp3.h" + +STATE states[MAX_STATE_COUNT]; +static EVENT events[MAX_EVENT_COUNT]; +static TRANSITION transitions[MAX_TRANSITION_COUNT]; +static int transition_count = 0; +int state_current = MP3_STATE_STARTUP; +static int state_previous = MP3_STATE_NONE; +static int shutdown = 0; + +void state_setup(void){ + EVENT_ADD(MP3_EVENT_TIMEOUT, "Timeout"); + EVENT_ADD(MP3_EVENT_FILE, "File"); + EVENT_ADD(MP3_EVENT_STREAM, "Stream"); + EVENT_ADD(MP3_EVENT_STOP, "Stop"); + EVENT_ADD(MP3_EVENT_ERROR, "Error"); + EVENT_ADD(MP3_EVENT_SHUTDOWN, "Shutdown"); + EVENT_ADD(MP3_EVENT_END, "End"); + + STATE_ADD(MP3_STATE_STARTUP, "Startup", state_startup_enter, NULL); + STATE_ADD(MP3_STATE_IDLE, "Idle", state_idle_enter, NULL); + STATE_ADD(MP3_STATE_FILE_START, "File startup", state_file_startup_enter, state_file_startup_leave); + STATE_ADD(MP3_STATE_FILE_HANDLE, "File handle", state_file_handle_enter, state_file_handle_leave); + STATE_ADD(MP3_STATE_STREAM_START, "Stream start", state_stream_startup_enter, state_stream_startup_leave); + STATE_ADD(MP3_STATE_STREAM_HANDLE, "Stream handle", state_stream_handle_enter, state_stream_handle_leave); + STATE_ADD(MP3_STATE_ERROR, "Error", state_error_enter, NULL); + STATE_ADD(MP3_STATE_SHUTDOWN, "Shutdown", state_shutdown_enter, NULL); + + TRANSITION_ADD(MP3_STATE_STARTUP, MP3_EVENT_TIMEOUT, MP3_STATE_IDLE); + + TRANSITION_ADD(MP3_STATE_IDLE, MP3_EVENT_TIMEOUT, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_IDLE, MP3_EVENT_FILE, MP3_STATE_FILE_START); + TRANSITION_ADD(MP3_STATE_IDLE, MP3_EVENT_STREAM, MP3_STATE_STREAM_START); + + TRANSITION_ADD(MP3_STATE_FILE_START, MP3_EVENT_TIMEOUT, MP3_STATE_FILE_HANDLE); + TRANSITION_ADD(MP3_STATE_FILE_START, MP3_EVENT_ERROR, MP3_STATE_ERROR); + + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_TIMEOUT, MP3_STATE_FILE_HANDLE); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_END, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_ERROR, MP3_STATE_ERROR); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_FILE, MP3_STATE_FILE_START); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_STOP, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_STREAM, MP3_STATE_STREAM_START); + + TRANSITION_ADD(MP3_STATE_STREAM_START, MP3_EVENT_TIMEOUT, MP3_STATE_STREAM_HANDLE); + TRANSITION_ADD(MP3_STATE_STREAM_START, MP3_EVENT_ERROR, MP3_STATE_ERROR); + + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_TIMEOUT, MP3_STATE_STREAM_HANDLE); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_STOP, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_ERROR, MP3_STATE_ERROR); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_FILE, MP3_STATE_FILE_START); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_STREAM, MP3_STATE_STREAM_START); + + TRANSITION_ADD(MP3_STATE_ERROR, MP3_EVENT_TIMEOUT, MP3_STATE_IDLE); + + TRANSITION_ADD(MP3_STATE_DEFAULT, MP3_EVENT_ERROR, MP3_STATE_ERROR); + TRANSITION_ADD(MP3_STATE_DEFAULT, MP3_EVENT_SHUTDOWN, MP3_STATE_SHUTDOWN); + state_startup_enter(0, 0, NULL); +}; + +void state_transition(int transition, int event, EVENT_PARAM *param){ + state_previous = state_current; + state_current = transitions[transition].new_state; + if(state_previous != state_current){ + printf("\n -- Transition %s -> %s\n", + states[state_previous].name, + states[state_current].name); + }; + if(states[state_previous].leave != NULL) + states[state_previous].leave(state_current, event); + if(states[state_current].enter != NULL) + states[state_current].enter(state_previous, event, param); + if(param){ + if(param->text){ + free(param->text); + }; + free(param); + }; +}; + +void state_event(int event, EVENT_PARAM *param){ + int i = 0; + if(event != MP3_EVENT_TIMEOUT){ + printf("\n -- Got event %s (%d) in state %s (%d)\n", + events[event].name, + event, + states[state_current].name, + state_current); + }; + for(i = 0; i < transition_count; i++){ + if((transitions[i].old_state == state_current) + && (transitions[i].event == event)){ + state_transition(i, event, param); + return; + }; + }; + for(i = 0; i < transition_count; i++){ + if((transitions[i].old_state == MP3_STATE_DEFAULT) + && (transitions[i].event == event)){ + state_transition(i, event, param); + return; + }; + }; + if(param){ + if(param->text){ + free(param->text); + }; + free(param); + }; + printf("Event %s not handled in state %s\n", events[event].name, states[state_current].name); +}; + +void state_mainloop(void){ + while(1){ + if(shutdown){ + state_event(MP3_EVENT_SHUTDOWN, NULL); + }; + mp3_nix_socket_handle(); + mp3_tcp_socket_handle(); + if(state_current == MP3_STATE_IDLE){ + poll(0, 0, 200); + } else { + poll(0, 0, 1); + }; + state_event(MP3_EVENT_TIMEOUT, NULL); + }; +}; + +EVENT_PARAM* state_new_event(unsigned char *text, int numeric){ + EVENT_PARAM *p = (EVENT_PARAM*)malloc(sizeof(EVENT_PARAM)); + if(text){ + p->text = strdup(text); + } else { + p->text = NULL; + }; + p->numeric = numeric; + return p; +}; + +void sig_handler(int sig){ + shutdown = 1; +}; + +int main(int argc, char **argv) { + unsigned char daemonize = 1; + + printf("\n\n"); + printf("ALPMP3 - MP3 Statemachine v1.0\n"); + + if(argc > 1){ + if(!strcmp(argv[1], "--no-daemon")){ + daemonize = 0; + } else { + printf("I am now going to daemonize. If you want me to stay in "); + printf("the foreground, add the parameter --no-daemon.\n"); + }; + }; + + if(daemonize){ + daemon(0, 0); + printf("----------------------------------------\n\n"); + printf("Made by openwrt.org (blogic@openwrt.org)\n"); + printf("\n"); + }; + + signal(SIGINT, sig_handler); + + state_setup(); + state_mainloop(); + + return 0; +} + + + + diff --git a/package/libjson-c/Makefile b/package/libjson-c/Makefile new file mode 100644 index 000000000..aa9db5162 --- /dev/null +++ b/package/libjson-c/Makefile @@ -0,0 +1,46 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# $Id: Makefile 6643 2007-03-23 08:11:08Z nico $ + +include $(TOPDIR)/rules.mk + +PKG_NAME:=json-c +PKG_VERSION:=0.7 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=http://oss.metaparadigm.com/json-c/ +PKG_MD5SUM:= + +include $(INCLUDE_DIR)/package.mk + +define Package/json-c + SECTION:=libs + CATEGORY:=Libraries + TITLE:=javascript object notation + DESCRIPTION:=library for javascript object notation backends + URL:=http://oss.metaparadigm.com/json-c/ +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CCOPT="$(TARGET_CFLAGS) -I$(BUILD_DIR)/linux/include" \ + DESTDIR="$(PKG_INSTALL_DIR)" \ + all install +endef + +define Build/InstallDev + mkdir -p $(STAGING_DIR)/ + $(CP) -r $(PKG_INSTALL_DIR)/* $(STAGING_DIR) +endef + +define Package/libpcap/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libjson.so.* $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,json-c)) |