| /******************************************************************************** |
| * Marvell GPL License Option |
| * |
| * If you received this File from Marvell, you may opt to use, redistribute and/or |
| * modify this File in accordance with the terms and conditions of the General |
| * Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| * available along with the File in the license.txt file or by writing to the Free |
| * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| * on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| * |
| * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| * DISCLAIMED. The GPL License provides additional details about this warranty |
| * disclaimer. |
| ******************************************************************************/ |
| #include <stdint.h> |
| |
| #include "util.h" |
| #include "apb_uart_drv.h" |
| #include "usb_common.h" |
| |
| static uint32_t output_string_buf_head; |
| void reset_usb_console(void) |
| { |
| output_string_buf_head = *(uint32_t*)USB_SOC_OUTPUT_WRITE_PTR; |
| if (output_string_buf_head == 0){ |
| output_string_buf_head = USB_SOC_OUTPUT_STRING_BUF; |
| } |
| } |
| |
| void usb_putc(int ch) |
| { |
| *(char *)output_string_buf_head = (char) ch; |
| output_string_buf_head ++; |
| if (output_string_buf_head >= USB_SOC_OUTPUT_STRING_BUF_ROLL_POINT){ |
| //roll back to start of the buffer, for next entire string. |
| *(uint32_t *)USB_SOC_OUTPUT_EOS_PTR = output_string_buf_head; |
| output_string_buf_head = USB_SOC_OUTPUT_STRING_BUF; |
| } |
| *(uint32_t *)USB_SOC_OUTPUT_WRITE_PTR = output_string_buf_head; |
| } |
| |
| int putchar(int c){ |
| APB_UART_putc(0, c) ; |
| usb_putc(c); |
| if (c == '\n'){ |
| APB_UART_putc(0, '\r'); |
| usb_putc('\r'); |
| flush_dcache_range((void *)USB_SOC_OUTPUT_WRITE_PTR, |
| (void *)ALIGNED(USB_SOC_OUTPUT_STRING_BUF + USB_SOC_STRING_BUF_SIZE)); |
| } |
| //Both usb_putc and UART_putc return void hence return 0 |
| return 0; |
| } |
| |
| void printchar(char **str, unsigned long *remain, int c) |
| { |
| |
| if (str) { |
| if (remain) { |
| if (*remain == 0) |
| return; |
| |
| // Only one spot left, nul terminate. |
| if (*remain == 1) |
| c = '\0'; |
| --(*remain); |
| } |
| |
| **str = c; |
| ++(*str); |
| } |
| else (void)putchar(c); |
| } |
| |
| #define PAD_RIGHT 1 |
| #define PAD_ZERO 2 |
| |
| int prints(char **out, unsigned long *remain, const char *string, int width, int pad) |
| { |
| register int pc = 0, padchar = ' '; |
| |
| if (width > 0) { |
| register int len = 0; |
| register const char *ptr; |
| for (ptr = string; *ptr; ++ptr) ++len; |
| if (len >= width) width = 0; |
| else width -= len; |
| if (pad & PAD_ZERO) padchar = '0'; |
| } |
| if (!(pad & PAD_RIGHT)) { |
| for ( ; width > 0; --width) { |
| printchar (out, remain, padchar); |
| ++pc; |
| } |
| } |
| for ( ; *string ; ++string) { |
| printchar (out, remain, *string); |
| ++pc; |
| } |
| for ( ; width > 0; --width) { |
| printchar (out, remain, padchar); |
| ++pc; |
| } |
| |
| return pc; |
| } |
| |
| /* the following should be enough for 32 bit int */ |
| #define PRINT_BUF_LEN 12 |
| |
| int printi(char **out, unsigned long* remain, int i, int b, int sg, int width, int pad, int letbase) |
| { |
| char print_buf[PRINT_BUF_LEN]; |
| register char *s; |
| register int t, neg = 0, pc = 0; |
| register unsigned int u = i; |
| |
| if (i == 0) { |
| print_buf[0] = '0'; |
| print_buf[1] = '\0'; |
| return prints (out, remain, print_buf, width, pad); |
| } |
| |
| if (sg && b == 10 && i < 0) { |
| neg = 1; |
| u = -i; |
| } |
| |
| s = print_buf + PRINT_BUF_LEN-1; |
| *s = '\0'; |
| |
| while (u) { |
| t = u % b; |
| if( t >= 10 ) |
| t += letbase - '0' - 10; |
| *--s = t + '0'; |
| u /= b; |
| } |
| |
| if (neg) { |
| if( width && (pad & PAD_ZERO) ) { |
| printchar (out, remain, '-'); |
| ++pc; |
| --width; |
| } |
| else { |
| *--s = '-'; |
| } |
| } |
| |
| return pc + prints (out, remain, s, width, pad); |
| } |
| |
| static int print(char **out, unsigned long *remain, int *varg) |
| { |
| register int width, pad; |
| register int pc = 0; |
| register char *format = (char *)(*varg++); |
| char scr[2]; |
| |
| for (; *format != 0; ++format) { |
| if (*format == '%') { |
| ++format; |
| width = pad = 0; |
| if (*format == '\0') break; |
| if (*format == '%') goto out; |
| if (*format == '-') { |
| ++format; |
| pad = PAD_RIGHT; |
| } |
| while (*format == '0') { |
| ++format; |
| pad |= PAD_ZERO; |
| } |
| for ( ; *format >= '0' && *format <= '9'; ++format) { |
| width *= 10; |
| width += *format - '0'; |
| } |
| if( *format == 's' ) { |
| register char *s = *((char **)varg++); |
| pc += prints (out, remain, s?s:"(null)", width, pad); |
| continue; |
| } |
| if( *format == 'd' ) { |
| pc += printi (out, remain, *varg++, 10, 1, width, pad, 'a'); |
| continue; |
| } |
| if( *format == 'x' ) { |
| pc += printi (out, remain, *varg++, 16, 0, width, pad, 'a'); |
| continue; |
| } |
| if( *format == 'X' ) { |
| pc += printi (out, remain ,*varg++, 16, 0, width, pad, 'A'); |
| continue; |
| } |
| if( *format == 'u' ) { |
| pc += printi (out, remain, *varg++, 10, 0, width, pad, 'a'); |
| continue; |
| } |
| if( *format == 'c' ) { |
| /* char are converted to int then pushed on the stack */ |
| scr[0] = *varg++; |
| scr[1] = '\0'; |
| pc += prints (out, remain ,scr, width, pad); |
| continue; |
| } |
| } |
| else { |
| out: |
| printchar (out, remain, *format); |
| ++pc; |
| } |
| } |
| if (out) **out = '\0'; |
| return pc; |
| } |
| |
| #if 0 |
| /* assuming sizeof(void *) == sizeof(int) */ |
| |
| int printf(const char *format, ...) |
| { |
| register int *varg = (int *)(&format); |
| return print(0, varg); |
| } |
| |
| int sprintf(char *out, const char *format, ...) |
| { |
| register int *varg = (int *)(&format); |
| return print(&out, varg); |
| } |
| #endif |
| |
| #if 1 |
| int lgpl_printf(const char *format, ...) |
| { |
| register int *varg = (int *)(&format); |
| return print(0, NULL, varg); |
| } |
| #endif |
| |
| int printf(const char *format, ...) |
| { |
| register int *varg = (int *)(&format); |
| return print(0, NULL, varg); |
| } |
| |
| #if 1 |
| int lgpl_sprintf(char *out, const char *format, ...) |
| { |
| register int *varg = (int *)(&format); |
| return print(&out, NULL, varg); |
| } |
| #endif |
| |
| int sprintf(char *out, const char *format, ...) |
| { |
| register int *varg = (int *)(&format); |
| return print(&out, NULL, varg); |
| } |
| |
| int snprintf(char *out, unsigned long size, const char *format, ...) |
| { |
| register int *varg = (int *)(&format); |
| return print(&out, &size, varg); |
| } |
| |
| /* |
| * if you compile this file with |
| * gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c |
| * you will get a normal warning: |
| * printf.c:214: warning: spurious trailing `%' in format |
| * this line is testing an invalid % at the end of the format string. |
| * |
| * this should display (on 32bit int machine) : |
| * |
| * Hello world! |
| * printf test |
| * (null) is null pointer |
| * 5 = 5 |
| * -2147483647 = - max int |
| * char a = 'a' |
| * hex ff = ff |
| * hex 00 = 00 |
| * signed -3 = unsigned 4294967293 = hex fffffffd |
| * 0 message(s) |
| * 0 message(s) with % |
| * justif: "left " |
| * justif: " right" |
| * 3: 0003 zero padded |
| * 3: 3 left justif. |
| * 3: 3 right justif. |
| * -3: -003 zero padded |
| * -3: -3 left justif. |
| * -3: -3 right justif. |
| */ |
| |