summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2002-04-23 09:13:23 +0000
committerBjörn Stenberg <bjorn@haxx.se>2002-04-23 09:13:23 +0000
commitc6773e1436ba3adda0a6456dbe54ba1320a095be (patch)
tree172c21804499aa84fcab2f755596a3272cfbd59a /firmware/drivers
parent34f948291202bdb42391bbc1200326e1aca00e5c (diff)
downloadrockbox-c6773e1436ba3adda0a6456dbe54ba1320a095be.tar.gz
rockbox-c6773e1436ba3adda0a6456dbe54ba1320a095be.zip
Moved driver to 'drivers' subdir
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@189 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/ata.c242
-rw-r--r--firmware/drivers/ata.h32
-rw-r--r--firmware/drivers/button.c197
-rw-r--r--firmware/drivers/button.h54
-rw-r--r--firmware/drivers/fat.c1315
-rw-r--r--firmware/drivers/fat.h154
-rw-r--r--firmware/drivers/i2c.c212
-rw-r--r--firmware/drivers/i2c.h33
-rw-r--r--firmware/drivers/lcd.c680
-rw-r--r--firmware/drivers/lcd.h162
-rw-r--r--firmware/drivers/led.c70
-rw-r--r--firmware/drivers/led.h50
-rw-r--r--firmware/drivers/mas.c164
-rw-r--r--firmware/drivers/mas.h54
-rw-r--r--firmware/drivers/serial.c75
-rw-r--r--firmware/drivers/serial.h31
16 files changed, 3525 insertions, 0 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
new file mode 100644
index 0000000000..cb4e1e6b90
--- /dev/null
+++ b/firmware/drivers/ata.c
@@ -0,0 +1,242 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "ata.h"
20#include "kernel.h"
21#include "led.h"
22
23#define ATA_DATA (*((volatile unsigned short*)0x06104100))
24#define ATA_ERROR (*((volatile unsigned char*)0x06100101))
25#define ATA_FEATURE ATA_ERROR
26#define ATA_NSECTOR (*((volatile unsigned char*)0x06100102))
27#define ATA_SECTOR (*((volatile unsigned char*)0x06100103))
28#define ATA_LCYL (*((volatile unsigned char*)0x06100104))
29#define ATA_HCYL (*((volatile unsigned char*)0x06100105))
30#define ATA_SELECT (*((volatile unsigned char*)0x06100106))
31#define ATA_COMMAND (*((volatile unsigned char*)0x06100107))
32#define ATA_STATUS ATA_COMMAND
33#define ATA_CONTROL (*((volatile unsigned char*)0x06100306))
34
35#define SELECT_LBA 0x40
36
37#define STATUS_BSY 0x80
38#define STATUS_RDY 0x40
39#define STATUS_DRQ 0x08
40#define STATUS_ERR 0x01
41
42#define CONTROL_nIEN 0x02
43#define CONTROL_SRST 0x04
44
45#define CMD_READ_SECTORS 0x20
46#define CMD_WRITE_SECTORS 0x30
47#define CMD_STANDBY_IMMEDIATE 0xE0
48#define CMD_STANDBY 0xE2
49#define CMD_SLEEP 0xE6
50#define CMD_SECURITY_FREEZE_LOCK 0xF5
51
52static int wait_for_bsy(void)
53{
54 char timeout = current_tick + HZ;
55 while (TIME_BEFORE(current_tick, timeout) && (ATA_STATUS & STATUS_BSY))
56 yield();
57
58 if (TIME_BEFORE(current_tick, timeout))
59 return 1;
60 else
61 return 0; /* timeout */
62}
63
64static int wait_for_rdy(void)
65{
66 if (!wait_for_bsy())
67 return 0;
68 return ATA_STATUS & STATUS_RDY;
69}
70
71static int wait_for_start_of_transfer(void)
72{
73 if (!wait_for_bsy())
74 return 0;
75 return (ATA_STATUS & (STATUS_RDY|STATUS_DRQ)) == (STATUS_RDY|STATUS_DRQ);
76}
77
78static int wait_for_end_of_transfer(void)
79{
80 if (!wait_for_bsy())
81 return 0;
82 return (ATA_STATUS & (STATUS_RDY|STATUS_DRQ)) == STATUS_RDY;
83}
84
85int ata_read_sectors(unsigned long start,
86 unsigned char count,
87 void* buf)
88{
89 int i;
90
91 if (!wait_for_rdy())
92 return 0;
93
94 led_turn_on();
95
96 ATA_NSECTOR = count;
97 ATA_SECTOR = start & 0xff;
98 ATA_LCYL = (start >> 8) & 0xff;
99 ATA_HCYL = (start >> 16) & 0xff;
100 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA;
101 ATA_COMMAND = CMD_READ_SECTORS;
102
103 for (i=0; i<count; i++) {
104 int j;
105 if (!wait_for_start_of_transfer())
106 return 0;
107
108 for (j=0; j<256; j++)
109 ((unsigned short*)buf)[j] = SWAB16(ATA_DATA);
110 }
111
112 led_turn_off();
113
114 return wait_for_end_of_transfer();
115}
116
117int ata_write_sectors(unsigned long start,
118 unsigned char count,
119 void* buf)
120{
121 int i;
122
123 if (!wait_for_rdy())
124 return 0;
125
126 led_turn_on ();
127
128 ATA_NSECTOR = count;
129 ATA_SECTOR = start & 0xff;
130 ATA_LCYL = (start >> 8) & 0xff;
131 ATA_HCYL = (start >> 16) & 0xff;
132 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA;
133 ATA_COMMAND = CMD_WRITE_SECTORS;
134
135 for (i=0; i<count; i++) {
136 int j;
137 if (!wait_for_start_of_transfer())
138 return 0;
139
140 for (j=0; j<256; j++)
141 ATA_DATA = SWAB16(((unsigned short*)buf)[j]);
142 }
143
144 led_turn_off ();
145
146 return wait_for_end_of_transfer();
147}
148
149static int check_registers(void)
150{
151 if ( ATA_STATUS & STATUS_BSY )
152 return 0;
153
154 ATA_NSECTOR = 0xa5;
155 ATA_SECTOR = 0x5a;
156 ATA_LCYL = 0xaa;
157 ATA_HCYL = 0x55;
158
159 if ((ATA_NSECTOR == 0xa5) &&
160 (ATA_SECTOR == 0x5a) &&
161 (ATA_LCYL == 0xaa) &&
162 (ATA_HCYL == 0x55))
163 return 1;
164 else
165 return 0;
166}
167
168static int check_harddisk(void)
169{
170 if (!wait_for_rdy())
171 return 0;
172
173 if ((ATA_NSECTOR == 1) &&
174 (ATA_SECTOR == 1) &&
175 (ATA_LCYL == 0) &&
176 (ATA_HCYL == 0) &&
177 (ATA_SELECT == 0))
178 return 1;
179 else
180 return 0;
181}
182
183static int freeze_lock(void)
184{
185 if (!wait_for_rdy())
186 return -1;
187
188 ATA_COMMAND = CMD_SECURITY_FREEZE_LOCK;
189
190 if (!wait_for_rdy())
191 return -1;
192
193 return 0;
194}
195
196int ata_hard_reset(void)
197{
198 clear_bit(1,PADR);
199 sleep(HZ/500);
200
201 set_bit(1,PADR);
202 sleep(HZ/500);
203
204 return wait_for_rdy();
205}
206
207int ata_soft_reset(void)
208{
209 ATA_SELECT = SELECT_LBA;
210 ATA_CONTROL = CONTROL_nIEN|CONTROL_SRST;
211 sleep(HZ/20000); /* >= 5us */
212
213 ATA_CONTROL = CONTROL_nIEN;
214 sleep(HZ/400); /* >2ms */
215
216 return wait_for_rdy();
217}
218
219int ata_init(void)
220{
221 led_turn_off();
222
223 /* activate ATA */
224 PADR |= 0x80;
225
226 if (!ata_hard_reset())
227 return -1;
228
229 if (!check_registers())
230 return -2;
231
232 if (!check_harddisk())
233 return -3;
234
235 if (!freeze_lock())
236 return -4;
237
238 ATA_SELECT = SELECT_LBA;
239 ATA_CONTROL = CONTROL_nIEN;
240
241 return 0;
242}
diff --git a/firmware/drivers/ata.h b/firmware/drivers/ata.h
new file mode 100644
index 0000000000..50cd85d755
--- /dev/null
+++ b/firmware/drivers/ata.h
@@ -0,0 +1,32 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef __ATA_H__
20#define __ATA_H__
21
22extern int ata_hard_reset(void);
23extern int ata_soft_reset(void);
24extern int ata_init(void);
25extern int ata_read_sectors(unsigned long start,
26 unsigned char count,
27 void* buf);
28extern int ata_write_sectors(unsigned long start,
29 unsigned char count,
30 void* buf);
31
32#endif
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
new file mode 100644
index 0000000000..a1abccd32a
--- /dev/null
+++ b/firmware/drivers/button.c
@@ -0,0 +1,197 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19/*
20 * Archos Jukebox Recorder button functions
21 */
22
23#include "config.h"
24#include "sh7034.h"
25#include "button.h"
26
27#ifdef HAVE_RECORDER_KEYPAD
28
29/* AJBR buttons are connected to the CPU as follows:
30 *
31 * ON and OFF are connected to separate port B input pins.
32 *
33 * F1, F2, F3, and UP are connected to the AN4 analog input, each through
34 * a separate voltage divider. The voltage on AN4 depends on which button
35 * (or none, or a combination) is pressed.
36 *
37 * DOWN, PLAY, LEFT, and RIGHT are likewise connected to AN5. */
38
39/* Button voltage levels on AN4 and AN5 */
40#define LEVEL1 50
41#define LEVEL2 125
42#define LEVEL3 175
43#define LEVEL4 225
44
45/* Number of calls to get_button for a button to stop bouncing
46 * and to be considered held down.
47 * Should really use a hardware timer for this.
48 */
49#define BOUNCE_COUNT 200
50#define HOLD_COUNT 10000
51
52static int last; /* Last button pressed */
53static int count; /* Number of calls button has been down */
54
55
56/*
57 *Initialize buttons
58 */
59void button_init()
60{
61#ifndef SIMULATOR
62 /* Set PB4 and PB8 as input pins */
63 PBCR1 &= 0xfffc; /* PB8MD = 00 */
64 PBCR2 &= 0xfcff; /* PB4MD = 00 */
65 PBIOR &= ~(PBDR_BTN_ON|PBDR_BTN_OFF); /* Inputs */
66
67 /* Set A/D to scan AN4 and AN5.
68 * This needs to be changed to scan other analog pins
69 * for battery level, etc. */
70 ADCSR = 0;
71 ADCR = 0;
72 ADCSR = ADCSR_ADST | ADCSR_SCAN | 0x5;
73#endif
74 last = BUTTON_NONE;
75 count = 0;
76}
77
78/*
79 * Get button pressed from hardware
80 */
81static int get_raw_button (void)
82{
83 /* Check port B pins for ON and OFF */
84 int data = PBDR;
85 if ((data & PBDR_BTN_ON) == 0)
86 return BUTTON_ON;
87 else if ((data & PBDR_BTN_OFF) == 0)
88 return BUTTON_OFF;
89
90 /* Check AN4 pin for F1-3 and UP */
91 data = ADDRAH;
92 if (data >= LEVEL4)
93 return BUTTON_F3;
94 else if (data >= LEVEL3)
95 return BUTTON_UP;
96 else if (data >= LEVEL2)
97 return BUTTON_F2;
98 else if (data >= LEVEL1)
99 return BUTTON_F1;
100
101 /* Check AN5 pin for DOWN, PLAY, LEFT, RIGHT */
102 data = ADDRBH;
103 if (data >= LEVEL4)
104 return BUTTON_DOWN;
105 else if (data >= LEVEL3)
106 return BUTTON_PLAY;
107 else if (data >= LEVEL2)
108 return BUTTON_LEFT;
109 else if (data >= LEVEL1)
110 return BUTTON_RIGHT;
111
112 return BUTTON_NONE;
113}
114
115/*
116 * Get the currently pressed button.
117 * Returns one of BUTTON_xxx codes, with possibly a modifier bit set.
118 * No modifier bits are set when the button is first pressed.
119 * BUTTON_HELD bit is while the button is being held.
120 * BUTTON_REL bit is set when button has been released.
121 */
122int button_get(void)
123{
124 int btn = get_raw_button();
125 int ret;
126
127 /* Last button pressed is still down */
128 if (btn != BUTTON_NONE && btn == last) {
129 count++;
130 if (count == BOUNCE_COUNT)
131 return btn;
132 else if (count >= HOLD_COUNT)
133 return btn | BUTTON_HELD;
134 else
135 return BUTTON_NONE;
136 }
137
138 /* Last button pressed now released */
139 if (btn == BUTTON_NONE && last != BUTTON_NONE)
140 ret = last | BUTTON_REL;
141 else
142 ret = BUTTON_NONE;
143
144 last = btn;
145 count = 0;
146 return ret;
147}
148
149#elif HAVE_PLAYER_KEYPAD
150
151/* The player has all buttons on port pins:
152
153 LEFT: PC0
154 RIGHT: PC2
155 PLAY: PC3
156 STOP: PA11
157 ON: PA5
158 MENU: PC1
159*/
160
161void button_init(void)
162{
163 /* set port pins as input */
164 PAIOR &= ~0x820;
165}
166
167int button_get(void)
168{
169 int porta = PADR;
170 int portc = PCDR;
171 int btn = 0;
172
173 if ( portc & 1 )
174 btn |= BUTTON_LEFT;
175 if ( portc & 2 )
176 btn |= BUTTON_MENU;
177 if ( portc & 4 )
178 btn |= BUTTON_RIGHT;
179 if ( portc & 8 )
180 btn |= BUTTON_PLAY | BUTTON_UP;
181 if ( porta & 0x20 )
182 btn |= BUTTON_ON;
183 if ( porta & 0x800 )
184 btn |= BUTTON_STOP | BUTTON_DOWN;
185
186 return btn;
187}
188
189#endif
190
191
192
193/* -----------------------------------------------------------------
194 * local variables:
195 * eval: (load-file "rockbox-mode.el")
196 * end:
197 */
diff --git a/firmware/drivers/button.h b/firmware/drivers/button.h
new file mode 100644
index 0000000000..a8cc71b875
--- /dev/null
+++ b/firmware/drivers/button.h
@@ -0,0 +1,54 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "config.h"
21
22void button_init (void);
23int button_get (void);
24
25/* Shared button codes */
26#define BUTTON_NONE 0x0000
27#define BUTTON_ON 0x0001
28#define BUTTON_UP 0x0010
29#define BUTTON_DOWN 0x0020
30#define BUTTON_LEFT 0x0040
31#define BUTTON_RIGHT 0x0080
32
33/* Button modifiers */
34#define BUTTON_HELD 0x4000
35#define BUTTON_REL 0x8000
36
37
38#ifdef HAVE_RECORDER_KEYPAD
39
40/* Recorder specific button codes */
41#define BUTTON_OFF 0x0002
42#define BUTTON_PLAY 0x0004
43#define BUTTON_F1 0x0100
44#define BUTTON_F2 0x0200
45#define BUTTON_F3 0x0400
46
47#elif HAVE_PLAYER_KEYPAD
48
49/* Jukebox 6000 and Studio specific button codes */
50#define BUTTON_MENU 0x0002
51#define BUTTON_PLAY BUTTON_UP
52#define BUTTON_STOP BUTTON_DOWN
53
54#endif
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
new file mode 100644
index 0000000000..328428a941
--- /dev/null
+++ b/firmware/drivers/fat.c
@@ -0,0 +1,1315 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <stdio.h>
21#include <string.h>
22#include <math.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <time.h>
26#include <sys/timeb.h>
27
28#define BLOCK_SIZE 512
29
30#include "fat.h"
31#include "ata.h"
32
33#define NUM_ROOT_DIR_ENTRIES 512
34#define NUM_FATS 2
35#define NUM_RESERVED_SECTORS 1
36#define NUM_BLOCKS 10000
37
38struct dsksz2secperclus
39{
40 unsigned int disk_size;
41 unsigned int sec_per_cluster;
42};
43
44/*
45** This is the table for FAT16 drives. NOTE that this table includes
46** entries for disk sizes larger than 512 MB even though typically
47** only the entries for disks < 512 MB in size are used.
48** The way this table is accessed is to look for the first entry
49** in the table for which the disk size is less than or equal
50** to the DiskSize field in that table entry. For this table to
51** work properly BPB_RsvdSecCnt must be 1, BPB_NumFATs
52** must be 2, and BPB_RootEntCnt must be 512. Any of these values
53** being different may require the first table entries DiskSize value
54** to be changed otherwise the cluster count may be to low for FAT16.
55*/
56struct dsksz2secperclus dsk_table_fat16 [] =
57{
58 { 8400, 0}, /* disks up to 4.1 MB, the 0 value for SecPerClusVal
59 trips an error */
60 { 32680, 2}, /* disks up to 16 MB, 1k cluster */
61 { 262144, 4}, /* disks up to 128 MB, 2k cluster */
62 { 524288, 8}, /* disks up to 256 MB, 4k cluster */
63 { 1048576, 16}, /* disks up to 512 MB, 8k cluster */
64/* The entries after this point are not used unless FAT16 is forced */
65 { 2097152, 32}, /* disks up to 1 GB, 16k cluster */
66 { 4194304, 64}, /* disks up to 2 GB, 32k cluster */
67 { 0xFFFFFFFF, 0} /* any disk greater than 2GB,
68 0 value for SecPerClusVal trips an error */
69};
70
71int fat_num_rootdir_sectors(struct bpb *bpb);
72int fat_first_sector_of_cluster(struct bpb *bpb, unsigned int cluster);
73int fat_get_fatsize(struct bpb* bpb);
74int fat_get_totsec(struct bpb* bpb);
75int fat_get_rootdir_sector(struct bpb *bpb);
76int fat_first_data_sector(struct bpb* bpb);
77int fat_get_bpb(struct bpb *bpb);
78int fat_bpb_is_sane(struct bpb *bpb);
79int fat_create_fat(struct bpb* bpb);
80int fat_dbg_read_block(char *name, unsigned char *buf);
81int fat_flush_fat(struct bpb *bpb);
82unsigned char *fat_cache_fat_sector(struct bpb *bpb, int secnum);
83int fat_update_entry(struct bpb *bpb, int entry, unsigned int val);
84unsigned int fat_getcurrdostime(unsigned short *dosdate,
85 unsigned short *dostime,
86 unsigned char *dostenth);
87int fat_create_root_dir(struct bpb *bpb);
88int fat_create_dos_name(unsigned char *name, unsigned char *newname);
89int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name);
90
91unsigned char *fat_cache[256];
92int fat_cache_dirty[256];
93char current_directory[256] = "\\";
94struct bpb *global_bpb;
95struct disk_info di;
96
97extern int yyparse(void);
98
99
100#ifdef TEST_FAT
101void prompt(void)
102{
103 printf("C:%s>", current_directory);
104}
105
106int main(int argc, char *argv[])
107{
108 struct bpb bpb;
109
110 memset(fat_cache, 0, sizeof(fat_cache));
111 memset(fat_cache_dirty, 0, sizeof(fat_cache_dirty));
112
113 disk_init(NUM_BLOCKS);
114
115 di.num_sectors = NUM_BLOCKS;
116 di.sec_per_track = 40;
117 di.num_heads = 250;
118 di.hidden_sectors = 0;
119
120 if(read_disk("diskdump.dmp") < 0)
121 {
122 printf("*** Warning! The disk is uninitialized\n");
123 }
124 else
125 {
126 fat_get_bpb(&bpb);
127 }
128
129 global_bpb = &bpb;
130 prompt();
131 yyparse();
132
133 dump_disk("diskdump.dmp");
134 return 0;
135}
136#endif
137
138int fat_sec2cluster(struct bpb *bpb, unsigned int sec)
139{
140 int first_sec = fat_first_data_sector(bpb);
141
142 if(sec < first_sec)
143 {
144 fprintf(stderr, "fat_sec2cluster() - Bad sector number (%d)\n", sec);
145 return -1;
146 }
147
148 return ((sec - first_sec) / bpb->bpb_secperclus) + 2;
149}
150
151int fat_last_cluster_in_chain(struct bpb *bpb, unsigned int cluster)
152{
153 int iseof = 0;
154
155 switch(bpb->fat_type)
156 {
157 case FATTYPE_FAT12:
158 if(cluster >= 0x0ff8)
159 iseof = 1;
160 break;
161 case FATTYPE_FAT16:
162 if(cluster >= 0xfff8)
163 iseof = 1;
164 break;
165 case FATTYPE_FAT32:
166 if(cluster >= 0x0ffffff8)
167 iseof = 1;
168 break;
169 }
170 return iseof;
171}
172
173int fat_cluster2sec(struct bpb *bpb, unsigned int cluster)
174{
175 int max_cluster = (fat_get_totsec(bpb) - fat_first_data_sector(bpb)) /
176 bpb->bpb_secperclus + 1;
177
178 if(cluster > max_cluster)
179 {
180 fprintf(stderr, "fat_cluster2sec() - Bad cluster number (%d)\n",
181 cluster);
182 return -1;
183 }
184
185 return fat_first_sector_of_cluster(bpb, cluster);
186}
187
188int fat_first_sector_of_cluster(struct bpb *bpb, unsigned int cluster)
189{
190 return (cluster - 2) * bpb->bpb_secperclus + fat_first_data_sector(bpb);
191}
192
193int fat_num_rootdir_sectors(struct bpb *bpb)
194{
195 return ((bpb->bpb_rootentcnt * 32) + (bpb->bpb_bytspersec - 1)) /
196 bpb->bpb_bytspersec;
197}
198
199int fat_get_fatsize(struct bpb* bpb)
200{
201 if(bpb->bpb_fatsz16 != 0)
202 return bpb->bpb_fatsz16;
203 else
204 return bpb->bpb_fatsz32;
205}
206
207int fat_get_totsec(struct bpb* bpb)
208{
209 if(bpb->bpb_totsec16 != 0)
210 return bpb->bpb_totsec16;
211 else
212 return bpb->bpb_totsec32;
213}
214
215int fat_get_rootdir_sector(struct bpb *bpb)
216{
217 return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fat_get_fatsize(bpb);
218}
219
220int fat_first_data_sector(struct bpb* bpb)
221{
222 int fatsz;
223 int rootdirsectors;
224
225 fatsz = fat_get_fatsize(bpb);
226
227 rootdirsectors = fat_num_rootdir_sectors(bpb);
228
229 return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz + rootdirsectors;
230}
231
232int fat_format(struct disk_info *di, char *vol_name)
233{
234 unsigned char buf[BLOCK_SIZE];
235 struct bpb bpb;
236 unsigned int root_dir_sectors;
237 unsigned int tmp1, tmp2;
238 int sec_per_clus = 0;
239 int fat_size;
240 int i = 0;
241 int err;
242
243 while(di->num_sectors > dsk_table_fat16[i].disk_size)
244 {
245 i++;
246 }
247
248 sec_per_clus = dsk_table_fat16[i].sec_per_cluster;
249
250 if(sec_per_clus == 0)
251 {
252 fprintf(stderr, "fat_format() - Bad disk size (%u)\n",
253 di->num_sectors);
254 return -1;
255 }
256
257 /* First calculate how many sectors we need for
258 the root directory */
259 root_dir_sectors = ((NUM_ROOT_DIR_ENTRIES * 32) +
260 (BLOCK_SIZE - 1)) / BLOCK_SIZE;
261
262 /* Now calculate the FAT size */
263 tmp1 = di->num_sectors - (NUM_RESERVED_SECTORS + root_dir_sectors);
264 tmp2 = (256 * sec_per_clus) + NUM_FATS;
265
266 fat_size = (tmp1 + (tmp2 - 1)) / tmp2;
267
268 /* Now create the BPB. We must be careful, so we really make
269 it little endian. */
270 memset(buf, 0xff, BLOCK_SIZE);
271
272 strncpy(&buf[BS_OEMNAME], "MSWIN4.1", 8);
273 buf[BPB_BYTSPERSEC] = BLOCK_SIZE & 0xff;
274 buf[BPB_BYTSPERSEC+1] = BLOCK_SIZE >> 8;
275 buf[BPB_SECPERCLUS] = sec_per_clus;
276 buf[BPB_RSVDSECCNT] = 1;
277 buf[BPB_RSVDSECCNT+1] = 0;
278 buf[BPB_NUMFATS] = 2;
279 buf[BPB_ROOTENTCNT] = NUM_ROOT_DIR_ENTRIES & 0xff;
280 buf[BPB_ROOTENTCNT+1] = NUM_ROOT_DIR_ENTRIES >> 8;
281 buf[BPB_TOTSEC16] = di->num_sectors & 0xff;
282 buf[BPB_TOTSEC16+1] = di->num_sectors >> 8;
283 buf[BPB_MEDIA] = 0xf0;
284 buf[BPB_FATSZ16] = fat_size & 0xff;
285 buf[BPB_FATSZ16+1] = fat_size >> 8;
286 buf[BPB_SECPERTRK] = di->sec_per_track & 0xff;
287 buf[BPB_SECPERTRK+1] = di->sec_per_track >> 8;
288 buf[BPB_NUMHEADS] = di->num_heads & 0xff;
289 buf[BPB_NUMHEADS+1] = di->num_heads >> 8;
290 buf[BPB_HIDDSEC] = di->hidden_sectors & 0xff;
291 buf[BPB_HIDDSEC+1] = (di->hidden_sectors >> 8) & 0xff;
292 buf[BPB_HIDDSEC+2] = (di->hidden_sectors >> 16) & 0xff;
293 buf[BPB_HIDDSEC+3] = (di->hidden_sectors >> 24) & 0xff;
294 buf[BPB_TOTSEC32] = 0;
295 buf[BPB_TOTSEC32+1] = 0;
296 buf[BPB_TOTSEC32+2] = 0;
297 buf[BPB_TOTSEC32+3] = 0;
298
299 buf[BS_DRVNUM] = 0;
300 buf[BS_RESERVED1] = 0;
301 buf[BS_BOOTSIG] = 0x29;
302 buf[BS_VOLID] = 0x78;
303 buf[BS_VOLID+1] = 0x56;
304 buf[BS_VOLID+2] = 0x34;
305 buf[BS_VOLID+3] = 0x12;
306 memset(&buf[BS_VOLLAB], ' ', 11);
307 strncpy(&buf[BS_VOLLAB], vol_name, MIN(11, strlen(vol_name));
308 strncpy(&buf[BS_FILSYSTYPE], "FAT16 ", 8);
309
310 /* The final signature */
311 buf[BPB_LAST_WORD] = 0x55;
312 buf[BPB_LAST_WORD+1] = 0xaa;
313
314 /* Now write the sector to disk */
315 err = ata_write_sectors(0,1,buf);
316 if(err)
317 {
318 fprintf(stderr, "fat_format() - Couldn't write BSB (error code %i)\n",
319 err);
320 return -1;
321 }
322
323 if(fat_get_bpb(&bpb) < 0)
324 {
325 fprintf(stderr, "fat_format() - Couldn't read BPB\n");
326 return -1;
327 }
328
329 if(fat_create_fat(&bpb) < 0)
330 {
331 fprintf(stderr, "fat_format() - Couldn't create FAT\n");
332 return -1;
333 }
334
335 if(fat_create_root_dir(&bpb) < 0)
336 {
337 fprintf(stderr, "fat_format() - Couldn't write root dir sector\n");
338 return -1;
339 }
340
341 return 0;
342}
343
344int fat_get_bpb(struct bpb *bpb)
345{
346 unsigned char buf[BLOCK_SIZE];
347 int err;
348 int fatsz;
349 int rootdirsectors;
350 int totsec;
351 int datasec;
352 int countofclusters;
353
354 /* Read the sector */
355 err = ata_read_sectors(0,1,buf);
356 if(err)
357 {
358 fprintf(stderr, "fat_get_bpb() - Couldn't read BPB (error code %i)\n",
359 err);
360 return -1;
361 }
362
363 memset(bpb, 0, sizeof(struct bpb));
364
365 strncpy(bpb->bs_oemname, &buf[BS_OEMNAME], 8);
366 bpb->bs_oemname[8] = 0;
367
368 bpb->bpb_bytspersec = buf[BPB_BYTSPERSEC] | (buf[BPB_BYTSPERSEC+1] << 8);
369 bpb->bpb_secperclus = buf[BPB_SECPERCLUS];
370 bpb->bpb_rsvdseccnt = buf[BPB_RSVDSECCNT] | (buf[BPB_RSVDSECCNT+1] << 8);
371 bpb->bpb_numfats = buf[BPB_NUMFATS];
372 bpb->bpb_rootentcnt = buf[BPB_ROOTENTCNT] | (buf[BPB_ROOTENTCNT+1] << 8);
373 bpb->bpb_totsec16 = buf[BPB_TOTSEC16] | (buf[BPB_TOTSEC16+1] << 8);
374 bpb->bpb_media = buf[BPB_MEDIA];
375 bpb->bpb_fatsz16 = buf[BPB_FATSZ16] | (buf[BPB_FATSZ16+1] << 8);
376 bpb->bpb_secpertrk = buf[BPB_SECPERTRK] | (buf[BPB_SECPERTRK+1] << 8);
377 bpb->bpb_numheads = buf[BPB_NUMHEADS] | (buf[BPB_NUMHEADS+1] << 8);
378 bpb->bpb_hiddsec = buf[BPB_HIDDSEC] | (buf[BPB_HIDDSEC+1] << 8) |
379 (buf[BPB_HIDDSEC+2] << 16) | (buf[BPB_HIDDSEC+3] << 24);
380 bpb->bpb_totsec32 = buf[BPB_TOTSEC32] | (buf[BPB_TOTSEC32+1] << 8) |
381 (buf[BPB_TOTSEC32+2] << 16) | (buf[BPB_TOTSEC32+3] << 24);
382
383 bpb->bs_drvnum = buf[BS_DRVNUM];
384 bpb->bs_bootsig = buf[BS_BOOTSIG];
385 if(bpb->bs_bootsig == 0x29)
386 {
387 bpb->bs_volid = buf[BS_VOLID] | (buf[BS_VOLID+1] << 8) |
388 (buf[BS_VOLID+2] << 16) | (buf[BS_VOLID+3] << 24);
389 strncpy(bpb->bs_vollab, &buf[BS_VOLLAB], 11);
390 strncpy(bpb->bs_filsystype, &buf[BS_FILSYSTYPE], 8);
391 }
392
393 bpb->bpb_fatsz32 = (buf[BPB_FATSZ32] + (buf[BPB_FATSZ32+1] << 8)) |
394 (buf[BPB_FATSZ32+2] << 16) | (buf[BPB_FATSZ32+3] << 24);
395
396 bpb->last_word = buf[BPB_LAST_WORD] | (buf[BPB_LAST_WORD+1] << 8);
397
398 /* Determine FAT type */
399 fatsz = fat_get_fatsize(bpb);
400
401 if(bpb->bpb_totsec16 != 0)
402 totsec = bpb->bpb_totsec16;
403 else
404 totsec = bpb->bpb_totsec32;
405
406 rootdirsectors = fat_num_rootdir_sectors(bpb);
407 datasec = totsec - (bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz +
408 rootdirsectors);
409 countofclusters = datasec / bpb->bpb_secperclus;
410
411 if(countofclusters < 4085)
412 {
413 bpb->fat_type = FATTYPE_FAT12;
414 }
415 else
416 {
417 if(countofclusters < 65525)
418 {
419 bpb->fat_type = FATTYPE_FAT16;
420 }
421 else
422 {
423 bpb->fat_type = FATTYPE_FAT32;
424 }
425 }
426
427 if(fat_bpb_is_sane(bpb) < 0)
428 {
429 fprintf(stderr, "fat_get_bpb() - BPB is not sane\n");
430 return -1;
431 }
432
433 return 0;
434}
435
436int fat_bpb_is_sane(struct bpb *bpb)
437{
438 if(bpb->fat_type == FATTYPE_FAT32)
439 {
440 fprintf(stderr, "fat_bpb_is_sane() - Error: FAT32 not supported\n");
441 return -1;
442 }
443
444 if(bpb->bpb_bytspersec != 512)
445 {
446 fprintf(stderr,
447 "fat_bpb_is_sane() - Warning: sector size is not 512 (%i)\n",
448 bpb->bpb_bytspersec);
449 }
450 if(bpb->bpb_secperclus * bpb->bpb_bytspersec > 32768)
451 {
452 fprintf(stderr,
453 "fat_bpb_is_sane() - Warning: cluster size is larger than 32K "
454 "(%i * %i = %i)\n",
455 bpb->bpb_bytspersec, bpb->bpb_secperclus,
456 bpb->bpb_bytspersec * bpb->bpb_secperclus);
457 }
458 if(bpb->bpb_rsvdseccnt != 1)
459 {
460 fprintf(stderr,
461 "fat_bpb_is_sane() - Warning: Reserved sectors is not 1 (%i)\n",
462 bpb->bpb_rsvdseccnt);
463 }
464 if(bpb->bpb_numfats != 2)
465 {
466 fprintf(stderr,
467 "fat_bpb_is_sane() - Warning: NumFATS is not 2 (%i)\n",
468 bpb->bpb_numfats);
469 }
470 if(bpb->bpb_rootentcnt != 512)
471 {
472 fprintf(stderr,
473 "fat_bpb_is_sane() - Warning: RootEntCnt is not 512 (%i)\n",
474 bpb->bpb_rootentcnt);
475 }
476 if(bpb->bpb_totsec16 < 200)
477 {
478 if(bpb->bpb_totsec16 == 0)
479 {
480 fprintf(stderr, "fat_bpb_is_sane() - Error: TotSec16 is 0\n");
481 return -1;
482 }
483 else
484 {
485 fprintf(stderr,
486 "fat_bpb_is_sane() - Warning: TotSec16 "
487 "is quite small (%i)\n",
488 bpb->bpb_totsec16);
489 }
490 }
491 if(bpb->bpb_media != 0xf0 && bpb->bpb_media < 0xf8)
492 {
493 fprintf(stderr,
494 "fat_bpb_is_sane() - Warning: Non-standard "
495 "media type (0x%02x)\n",
496 bpb->bpb_media);
497 }
498 if(bpb->last_word != 0xaa55)
499 {
500 fprintf(stderr, "fat_bpb_is_sane() - Error: Last word is not "
501 "0xaa55 (0x%04x)\n", bpb->last_word);
502 return -1;
503 }
504 return 0;
505}
506
507int fat_create_fat(struct bpb* bpb)
508{
509 unsigned char *sec;
510 int i;
511 int secnum = 0;
512 int fatsz;
513
514 if(fat_bpb_is_sane(bpb) < 0)
515 {
516 fprintf(stderr, "fat_create_fat() - BPB is not sane\n");
517 return -1;
518 }
519
520 if(bpb->bpb_fatsz16 != 0)
521 fatsz = bpb->bpb_fatsz16;
522 else
523 fatsz = bpb->bpb_fatsz32;
524
525 sec = fat_cache_fat_sector(bpb, secnum);
526 if(!sec)
527 {
528 fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector"
529 " (%d)\n", secnum);
530 return -1;
531 }
532
533 fat_cache_dirty[secnum] = 1;
534
535 /* First entry should have the media type in the
536 low byte and the rest of the bits set to 1.
537 The second should be the EOC mark. */
538 memset(sec, 0, BLOCK_SIZE);
539 sec[0] = bpb->bpb_media;
540 if(bpb->fat_type == FATTYPE_FAT12)
541 {
542 sec[1] = 0xff;
543 sec[2] = 0xff;
544 }
545 if(bpb->fat_type == FATTYPE_FAT16)
546 {
547 sec[0] = bpb->bpb_media;
548 sec[1] = 0xff;
549 sec[2] = 0xff;
550 sec[3] = 0xff;
551 }
552 secnum++;
553
554 for(i = 0; i < fatsz - 1;i++)
555 {
556 sec = fat_cache_fat_sector(bpb, secnum);
557 if(!sec)
558 {
559 fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector"
560 " (%d)\n", i);
561 return -1;
562 }
563 fat_cache_dirty[secnum] = 1;
564 secnum++;
565 memset(sec, 0, BLOCK_SIZE);
566 }
567
568 if(fat_flush_fat(bpb) < 0)
569 {
570 fprintf(stderr, "fat_create_fat() - Couldn't flush fat\n");
571 return -1;
572 }
573 return 0;
574}
575
576int fat_dbg_read_block(char *name, unsigned char *buf)
577{
578 FILE *f;
579
580 f = fopen(name, "rb");
581 if(f)
582 {
583 if(fread(buf, 1, 512, f) != 512)
584 {
585 fprintf(stderr, "Could not read file \"%s\"\n", name);
586 fclose(f);
587 return -1;
588 }
589 /* Now write the sector to disk */
590 ata_write_sectors(0,1,buf);
591 fclose(f);
592 }
593 else
594 {
595 fprintf(stderr, "Could not open file \"%s\"\n", name);
596 return -1;
597 }
598 return 0;
599}
600
601unsigned char *fat_cache_fat_sector(struct bpb *bpb, int secnum)
602{
603 unsigned char *sec;
604
605 sec = fat_cache[secnum];
606 /* Load the sector if it is not cached */
607 if(!sec)
608 {
609 sec = malloc(bpb->bpb_bytspersec);
610 if(!sec)
611 {
612 fprintf(stderr, "fat_cache_fat_sector() - Out of memory\n");
613 return NULL;
614 }
615 if(ata_read_sectors(secnum + bpb->bpb_rsvdseccnt,1,sec))
616 {
617 fprintf(stderr, "fat_cache_fat_sector() - Could"
618 " not read sector %d\n",
619 secnum);
620 free(sec);
621 return NULL;
622 }
623 fat_cache[secnum] = sec;
624 }
625 return sec;
626}
627
628int fat_update_entry(struct bpb *bpb, int entry, unsigned int val)
629{
630 unsigned char *sec;
631 unsigned char *sec2;
632 int fatsz;
633 int fatoffset;
634 int thisfatsecnum;
635 int thisfatentoffset;
636 unsigned int tmp;
637
638 fatsz = fat_get_fatsize(bpb);
639
640 if(bpb->fat_type == FATTYPE_FAT12)
641 {
642 fatoffset = entry + (entry / 2);
643 }
644 else
645 {
646 if(bpb->fat_type == FATTYPE_FAT16)
647 fatoffset = entry * 2;
648 else
649 fatoffset = entry * 4;
650 }
651 thisfatsecnum = fatoffset / bpb->bpb_bytspersec;
652 thisfatentoffset = fatoffset % bpb->bpb_bytspersec;
653
654 sec = fat_cache_fat_sector(bpb, thisfatsecnum);
655 /* Load the sector if it is not cached */
656 if(!sec)
657 {
658 fprintf(stderr, "fat_update_entry() - Could not cache sector %d\n",
659 thisfatsecnum);
660 return -1;
661 }
662
663 fat_cache_dirty[thisfatsecnum] = 1;
664
665 switch(bpb->fat_type)
666 {
667 case FATTYPE_FAT12:
668 if(thisfatentoffset == bpb->bpb_bytspersec - 1)
669 {
670 /* This entry spans a sector boundary. Take care */
671 sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1);
672 /* Load the sector if it is not cached */
673 if(!sec2)
674 {
675 fprintf(stderr, "fat_update_entry() - Could not "
676 "cache sector %d\n",
677 thisfatsecnum + 1);
678 return -1;
679 }
680 fat_cache_dirty[thisfatsecnum + 1] = 1;
681 }
682 else
683 {
684 if(entry & 1) /* Odd entry number? */
685 {
686 tmp = sec[thisfatentoffset] & 0xf0;
687 sec[thisfatentoffset] = tmp | (val & 0x0f);
688 sec[thisfatentoffset+1] = (val >> 4) & 0xff;
689 }
690 else
691 {
692 sec[thisfatentoffset] = val & 0xff;
693 tmp = sec[thisfatentoffset+1] & 0x0f;
694 sec[thisfatentoffset+1] = tmp | ((val >> 4) & 0xf0);
695 }
696 }
697 break;
698 case FATTYPE_FAT16:
699 *(unsigned short *)(&sec[thisfatentoffset]) = val;
700 break;
701 case FATTYPE_FAT32:
702 tmp = *(unsigned short *)(&sec[thisfatentoffset]) & 0xf000000;
703 val = tmp | (val & 0x0fffffff);
704 *(unsigned short *)(&sec[thisfatentoffset]) = val;
705 break;
706 }
707 return 0;
708}
709
710int fat_read_entry(struct bpb *bpb, int entry)
711{
712 unsigned char *sec;
713 unsigned char *sec2;
714 int fatsz;
715 int fatoffset;
716 int thisfatsecnum;
717 int thisfatentoffset;
718 int val = -1;
719
720 fatsz = fat_get_fatsize(bpb);
721
722 if(bpb->fat_type == FATTYPE_FAT12)
723 {
724 fatoffset = entry + (entry / 2);
725 }
726 else
727 {
728 if(bpb->fat_type == FATTYPE_FAT16)
729 fatoffset = entry * 2;
730 else
731 fatoffset = entry * 4;
732 }
733 thisfatsecnum = fatoffset / bpb->bpb_bytspersec;
734 thisfatentoffset = fatoffset % bpb->bpb_bytspersec;
735
736 sec = fat_cache_fat_sector(bpb, thisfatsecnum);
737 /* Load the sector if it is not cached */
738 if(!sec)
739 {
740 fprintf(stderr, "fat_update_entry() - Could not cache sector %d\n",
741 thisfatsecnum);
742 return -1;
743 }
744
745 switch(bpb->fat_type)
746 {
747 case FATTYPE_FAT12:
748 if(thisfatentoffset == bpb->bpb_bytspersec - 1)
749 {
750 /* This entry spans a sector boundary. Take care */
751 sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1);
752 /* Load the sector if it is not cached */
753 if(!sec2)
754 {
755 fprintf(stderr, "fat_update_entry() - Could not "
756 "cache sector %d\n",
757 thisfatsecnum + 1);
758 return -1;
759 }
760 }
761 else
762 {
763 if(entry & 1) /* Odd entry number? */
764 {
765 val = (sec[thisfatentoffset] & 0x0f) |
766 (sec[thisfatentoffset+1] << 4);
767 }
768 else
769 {
770 val = (sec[thisfatentoffset] & 0xff) |
771 ((sec[thisfatentoffset+1] & 0x0f) << 8);
772 }
773 }
774 break;
775 case FATTYPE_FAT16:
776 val = *(unsigned short *)(&sec[thisfatentoffset]);
777 break;
778 case FATTYPE_FAT32:
779 val = *(unsigned int *)(&sec[thisfatentoffset]);
780 break;
781 }
782 return val;
783}
784
785int fat_flush_fat(struct bpb *bpb)
786{
787 int i;
788 int err;
789 unsigned char *sec;
790 int fatsz;
791 unsigned short d, t;
792 char m;
793
794 fatsz = fat_get_fatsize(bpb);
795
796 for(i = 0;i < 256;i++)
797 {
798 if(fat_cache[i] && fat_cache_dirty[i])
799 {
800 printf("Flushing FAT sector %d\n", i);
801 sec = fat_cache[i];
802 err = ata_write_sectors(i + bpb->bpb_rsvdseccnt,1,sec);
803 if(err)
804 {
805 fprintf(stderr, "fat_flush_fat() - Couldn't write"
806 " sector (%d)\n", i + bpb->bpb_rsvdseccnt);
807 return -1;
808 }
809 err = ata_write_sectors(i + bpb->bpb_rsvdseccnt + fatsz,1,sec);
810 if(err)
811 {
812 fprintf(stderr, "fat_flush_fat() - Couldn't write"
813 " sector (%d)\n", i + bpb->bpb_rsvdseccnt + fatsz);
814 return -1;
815 }
816 fat_cache_dirty[i] = 0;
817 }
818 }
819
820 fat_getcurrdostime(&d, &t, &m);
821 return 0;
822}
823
824unsigned int fat_getcurrdostime(unsigned short *dosdate,
825 unsigned short *dostime,
826 unsigned char *dostenth)
827{
828 struct timeb tb;
829 struct tm *tm;
830
831 ftime(&tb);
832 tm = localtime(&tb.time);
833
834 *dosdate = ((tm->tm_year - 80) << 9) |
835 ((tm->tm_mon + 1) << 5) |
836 (tm->tm_mday);
837
838 *dostime = (tm->tm_hour << 11) |
839 (tm->tm_min << 5) |
840 (tm->tm_sec >> 1);
841
842 *dostenth = (tm->tm_sec & 1) * 100 + tb.millitm / 10;
843 return 0;
844}
845
846int fat_create_root_dir(struct bpb *bpb)
847{
848 unsigned char buf[BLOCK_SIZE];
849 int fatsz;
850 int sec;
851 int res;
852 int i;
853 unsigned short dosdate;
854 unsigned short dostime;
855 unsigned char dostenth;
856 int num_root_sectors;
857
858 fatsz = fat_get_fatsize(bpb);
859
860 sec = bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz;
861
862 memset(buf, 0, sizeof(buf));
863
864 strncpy(&buf[FATDIR_NAME], bpb->bs_vollab, 11);
865 buf[FATDIR_ATTR] = FAT_ATTR_VOLUME_ID;
866 buf[FATDIR_NTRES] = 0;
867
868 fat_getcurrdostime(&dosdate, &dostime, &dostenth);
869 buf[FATDIR_WRTDATE] = dosdate & 0xff;
870 buf[FATDIR_WRTDATE+1] = dosdate >> 8;
871 buf[FATDIR_WRTTIME] = dostime & 0xff;
872 buf[FATDIR_WRTTIME+1] = dostime >> 8;
873
874 printf("Writing rootdir to sector %d...\n", sec);
875
876 res = ata_write_sectors(sec,1,buf);
877 if(res)
878 {
879 fprintf(stderr, "fat_create_root_dir() - Couldn't write sector (%d)\n",
880 sec);
881 return -1;
882 }
883
884 printf("Clearing the rest of the root dir.\n");
885 sec++;
886 num_root_sectors = bpb->bpb_rootentcnt * 32 / bpb->bpb_bytspersec;
887 memset(buf, 0, BLOCK_SIZE);
888
889 for(i = 1;i < num_root_sectors;i++)
890 {
891 if(ata_write_sectors(sec++,1,buf))
892 {
893 fprintf(stderr, "fat_create_root_dir() - "
894 " Couldn't write sector (%d)\n", sec);
895 return -1;
896 }
897 }
898
899 return 0;
900}
901
902int fat_get_next_cluster(struct bpb *bpb, unsigned int cluster)
903{
904 int next_cluster = fat_read_entry(bpb, cluster);
905
906 if(fat_last_cluster_in_chain(bpb, next_cluster))
907 return 0;
908 else
909 return next_cluster;
910}
911
912int fat_add_dir_entry(struct bpb *bpb, unsigned int currdir,
913 struct fat_direntry *de)
914{
915 unsigned char buf[BLOCK_SIZE];
916 unsigned char *eptr;
917 int i;
918 int err;
919 unsigned int sec;
920 unsigned int sec_cnt;
921 int need_to_update_last_empty_marker = 0;
922 int is_rootdir = (currdir == 0);
923 int done = 0;
924 unsigned char firstbyte;
925
926 if(is_rootdir)
927 {
928 sec = fat_get_rootdir_sector(bpb);
929 }
930 else
931 {
932 sec = fat_first_sector_of_cluster(bpb, currdir);
933 }
934
935 sec_cnt = 0;
936
937 while(!done)
938 {
939 /* The root dir has a fixed size */
940 if(is_rootdir)
941 {
942 if(sec_cnt >= bpb->bpb_rootentcnt * 32 / bpb->bpb_bytspersec)
943 {
944 /* We have reached the last sector of the root dir */
945 if(need_to_update_last_empty_marker)
946 {
947 /* Since the directory is full, there is no room for
948 a marker, so we just exit */
949 return 0;
950 }
951 else
952 {
953 fprintf(stderr, "fat_add_dir_entry() -"
954 " Root dir is full\n");
955 return -1;
956 }
957 }
958 }
959 else
960 {
961 if(sec_cnt >= bpb->bpb_secperclus)
962 {
963 /* We have reached the end of this cluster */
964 printf("Moving to the next cluster...");
965 currdir = fat_get_next_cluster(bpb, currdir);
966 printf("new cluster is %d\n", currdir);
967
968 if(!currdir)
969 {
970 /* This was the last in the chain,
971 we have to allocate a new cluster */
972 /* TODO */
973 }
974 }
975 }
976
977 printf("Reading sector %d...\n", sec);
978 /* Read the next sector in the current dir */
979 err = ata_read_sectors(sec,1,buf);
980 if(err)
981 {
982 fprintf(stderr, "fat_add_dir_entry() - Couldn't read dir sector"
983 " (error code %i)\n", err);
984 return -1;
985 }
986
987 if(need_to_update_last_empty_marker)
988 {
989 /* All we need to do is to set the first entry to 0 */
990 printf("Clearing the first entry in sector %d\n", sec);
991 buf[0] = 0;
992 done = 1;
993 }
994 else
995 {
996 /* Look for a free slot */
997 for(i = 0;i < BLOCK_SIZE;i+=32)
998 {
999 firstbyte = buf[i];
1000 if(firstbyte == 0xe5 || firstbyte == 0)
1001 {
1002 printf("Found free slot at entry %d in sector %d\n",
1003 i/32, sec);
1004 eptr = &buf[i];
1005 memset(eptr, 0, 32);
1006 strncpy(&eptr[FATDIR_NAME], de->name, 11);
1007 eptr[FATDIR_ATTR] = de->attr;
1008 eptr[FATDIR_NTRES] = 0;
1009
1010 eptr[FATDIR_CRTTIMETENTH] = de->crttimetenth;
1011 eptr[FATDIR_CRTDATE] = de->crtdate & 0xff;
1012 eptr[FATDIR_CRTDATE+1] = de->crtdate >> 8;
1013 eptr[FATDIR_CRTTIME] = de->crttime & 0xff;
1014 eptr[FATDIR_CRTTIME+1] = de->crttime >> 8;
1015
1016 eptr[FATDIR_WRTDATE] = de->wrtdate & 0xff;
1017 eptr[FATDIR_WRTDATE+1] = de->wrtdate >> 8;
1018 eptr[FATDIR_WRTTIME] = de->wrttime & 0xff;
1019 eptr[FATDIR_WRTTIME+1] = de->wrttime >> 8;
1020
1021 eptr[FATDIR_FILESIZE] = de->filesize & 0xff;
1022 eptr[FATDIR_FILESIZE+1] = (de->filesize >> 8) & 0xff;
1023 eptr[FATDIR_FILESIZE+2] = (de->filesize >> 16) & 0xff;
1024 eptr[FATDIR_FILESIZE+3] = (de->filesize >> 24) & 0xff;
1025
1026 /* Advance the last_empty_entry marker */
1027 if(firstbyte == 0)
1028 {
1029 i += 32;
1030 if(i < BLOCK_SIZE)
1031 {
1032 buf[i] = 0;
1033 /* We are done */
1034 done = 1;
1035 }
1036 else
1037 {
1038 /* We must fill in the first entry
1039 in the next sector */
1040 need_to_update_last_empty_marker = 1;
1041 }
1042 }
1043
1044 err = ata_write_sectors(sec,1,buf);
1045 if(err)
1046 {
1047 fprintf(stderr, "fat_add_dir_entry() - "
1048 " Couldn't write dir"
1049 " sector (error code %i)\n", err);
1050 return -1;
1051 }
1052 break;
1053 }
1054 }
1055 }
1056 sec++;
1057 sec_cnt++;
1058 }
1059
1060 return 0;
1061}
1062
1063unsigned char fat_char2dos(unsigned char c)
1064{
1065 switch(c)
1066 {
1067 case 0xe5: /* Special kanji character */
1068 c = 0x05;
1069 break;
1070 case 0x22:
1071 case 0x2a:
1072 case 0x2b:
1073 case 0x2c:
1074 case 0x2e:
1075 case 0x3a:
1076 case 0x3b:
1077 case 0x3c:
1078 case 0x3d:
1079 case 0x3e:
1080 case 0x3f:
1081 case 0x5b:
1082 case 0x5c:
1083 case 0x5d:
1084 case 0x7c:
1085 /* Illegal name */
1086 c = 0;
1087 break;
1088
1089 default:
1090 if(c < 0x20)
1091 {
1092 /* Illegal name */
1093 c = 0;
1094 }
1095 break;
1096 }
1097 return c;
1098}
1099
1100int fat_create_dos_name(unsigned char *name, unsigned char *newname)
1101{
1102 unsigned char n[12];
1103 unsigned char c;
1104 int i;
1105 char *ext;
1106
1107 if(strlen(name) > 12)
1108 {
1109 return -1;
1110 }
1111
1112 strcpy(n, name);
1113
1114 ext = strchr(n, '.');
1115 if(ext)
1116 {
1117 *ext++ = 0;
1118 }
1119
1120 /* The file name is either empty, or there was only an extension.
1121 In either case it is illegal. */
1122 if(n[0] == 0)
1123 {
1124 return -1;
1125 }
1126
1127 /* Name part */
1128 for(i = 0;n[i] && (i < 8);i++)
1129 {
1130 c = fat_char2dos(n[i]);
1131 if(c)
1132 {
1133 newname[i] = toupper(c);
1134 }
1135 }
1136 while(i < 8)
1137 {
1138 newname[i++] = ' ';
1139 }
1140
1141 /* Extension part */
1142 for(i = 0;ext && ext[i] && (i < 3);i++)
1143 {
1144 c = fat_char2dos(ext[i]);
1145 if(c)
1146 {
1147 newname[8+i] = toupper(c);
1148 }
1149 }
1150 while(i < 3)
1151 {
1152 newname[8+i++] = ' ';
1153 }
1154 return 0;
1155}
1156
1157int fat_create_dir(struct bpb *bpb, unsigned int currdir, char *name)
1158{
1159 struct fat_direntry de;
1160 int err;
1161
1162 printf("fat_create_file()\n");
1163 memset(&de, 0, sizeof(struct fat_direntry));
1164 if(fat_create_dos_name(name, de.name) < 0)
1165 {
1166 fprintf(stderr, "fat_create_file() - Illegal file name (%s)\n", name);
1167 return -1;
1168 }
1169
1170 fat_getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth);
1171 de.wrtdate = de.crtdate;
1172 de.wrttime = de.crttime;
1173 de.filesize = 0;
1174 de.attr = FAT_ATTR_DIRECTORY;
1175
1176 err = fat_add_dir_entry(bpb, currdir, &de);
1177 return 0;
1178}
1179
1180int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name)
1181{
1182 struct fat_direntry de;
1183 int err;
1184
1185 printf("fat_create_file()\n");
1186 memset(&de, 0, sizeof(struct fat_direntry));
1187 if(fat_create_dos_name(name, de.name) < 0)
1188 {
1189 fprintf(stderr, "fat_create_file() - Illegal file name (%s)\n", name);
1190 return -1;
1191 }
1192 fat_getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth);
1193 de.wrtdate = de.crtdate;
1194 de.wrttime = de.crttime;
1195 de.filesize = 0;
1196
1197 err = fat_add_dir_entry(bpb, currdir, &de);
1198 return err;
1199}
1200
1201void fat_fill_direntry(struct fat_direntry *de, char *buf)
1202{
1203 memset(de, 0, sizeof(struct fat_direntry));
1204
1205 strncpy(de->name, &buf[FATDIR_NAME], 11);
1206 de->attr = buf[FATDIR_ATTR];
1207 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1208 de->crtdate = buf[FATDIR_CRTDATE] | (buf[FATDIR_CRTDATE+1] << 8);
1209 de->crttime = buf[FATDIR_CRTTIME] | (buf[FATDIR_CRTTIME+1] << 8);
1210 de->wrtdate = buf[FATDIR_WRTDATE] | (buf[FATDIR_WRTDATE+1] << 8);
1211 de->wrttime = buf[FATDIR_WRTTIME] | (buf[FATDIR_WRTTIME+1] << 8);
1212
1213 de->filesize = buf[FATDIR_FILESIZE] |
1214 (buf[FATDIR_FILESIZE+1] << 8) |
1215 (buf[FATDIR_FILESIZE+2] << 16) |
1216 (buf[FATDIR_FILESIZE+3] << 24);
1217}
1218
1219int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir)
1220{
1221 int is_rootdir = (currdir == 0);
1222 unsigned int sec;
1223 int err;
1224
1225 if(is_rootdir)
1226 {
1227 sec = fat_get_rootdir_sector(bpb);
1228 }
1229 else
1230 {
1231 sec = fat_first_sector_of_cluster(bpb, currdir);
1232 }
1233
1234 /* Read the first sector in the current dir */
1235 err = ata_read_sectors(sec,1,ent->cached_buf);
1236 if(err)
1237 {
1238 fprintf(stderr, "fat_getfirst() - Couldn't read dir sector"
1239 " (error code %i)\n", err);
1240 return -1;
1241 }
1242
1243 ent->entry = 0;
1244 ent->cached_sec = sec;
1245 ent->num_sec = 0;
1246 return 0;
1247}
1248
1249int fat_getnext(struct bpb *bpb, struct fat_dirent *ent,
1250 struct fat_direntry *entry)
1251{
1252 int done = 0;
1253 int i;
1254 int err;
1255 unsigned char firstbyte;
1256
1257 while(!done)
1258 {
1259 /* Look for a free slot */
1260 for(i = ent->entry;i < BLOCK_SIZE/32;i++)
1261 {
1262 firstbyte = ent->cached_buf[i*32];
1263 if(firstbyte == 0xe5)
1264 {
1265 continue;
1266 }
1267
1268 if(firstbyte == 0)
1269 {
1270 return -1;
1271 }
1272
1273 fat_fill_direntry(entry, &ent->cached_buf[i*32]);
1274 done = 1;
1275 break;
1276 }
1277
1278 /* Next sector? */
1279 if(i >= BLOCK_SIZE/32)
1280 {
1281 ent->num_sec++;
1282 ent->cached_sec++;
1283
1284 /* Do we need to advance one cluster? */
1285 if(ent->num_sec >= bpb->bpb_secperclus)
1286 {
1287 ent->num_sec = 0;
1288 ent->cached_sec = fat_get_next_cluster(
1289 bpb, fat_sec2cluster(bpb, ent->cached_sec));
1290 if(!ent->cached_sec)
1291 {
1292 printf("End of cluster chain.\n");
1293 return -1;
1294 }
1295 }
1296
1297 /* Read the next sector */
1298 err = ata_read_sectors(ent->cached_sec,1,ent->cached_buf);
1299 if(err)
1300 {
1301 fprintf(stderr, "fat_getnext() - Couldn't read dir sector"
1302 " (error code %i)\n", err);
1303 return -1;
1304 }
1305
1306 i = 0;
1307 }
1308 else
1309 {
1310 i++;
1311 }
1312 ent->entry = i;
1313 }
1314 return 0;
1315}
diff --git a/firmware/drivers/fat.h b/firmware/drivers/fat.h
new file mode 100644
index 0000000000..f1dc8dc5a0
--- /dev/null
+++ b/firmware/drivers/fat.h
@@ -0,0 +1,154 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef FAT_H
21#define FAT_H
22
23#define FATTYPE_FAT12 0
24#define FATTYPE_FAT16 1
25#define FATTYPE_FAT32 2
26
27#define BS_JMPBOOT 0
28#define BS_OEMNAME 3
29#define BPB_BYTSPERSEC 11
30#define BPB_SECPERCLUS 13
31#define BPB_RSVDSECCNT 14
32#define BPB_NUMFATS 16
33#define BPB_ROOTENTCNT 17
34#define BPB_TOTSEC16 19
35#define BPB_MEDIA 21
36#define BPB_FATSZ16 22
37#define BPB_SECPERTRK 24
38#define BPB_NUMHEADS 26
39#define BPB_HIDDSEC 28
40#define BPB_TOTSEC32 32
41
42#define BS_DRVNUM 36
43#define BS_RESERVED1 37
44#define BS_BOOTSIG 38
45#define BS_VOLID 39
46#define BS_VOLLAB 43
47#define BS_FILSYSTYPE 54
48
49#define BPB_FATSZ32 36
50
51#define BPB_LAST_WORD 510
52
53#define MIN(a,b) (((a) < (b))?(a):(b)))
54
55struct bpb
56{
57 char bs_oemname[9]; /* OEM string, ending with \0 */
58 int bpb_bytspersec; /* Bytes per sectory, typically 512 */
59 int bpb_secperclus; /* Sectors per cluster */
60 int bpb_rsvdseccnt; /* Number of reserved sectors */
61 int bpb_numfats; /* Number of FAT structures, typically 2 */
62 int bpb_rootentcnt; /* Number of dir entries in the root */
63 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
64 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
65 int bpb_fatsz16; /* Number of used sectors per FAT structure */
66 int bpb_secpertrk; /* Number of sectors per track */
67 int bpb_numheads; /* Number of heads */
68 int bpb_hiddsec; /* Hidden sectors before the volume */
69 unsigned int bpb_totsec32; /* Number of sectors on the volume
70 (new 32-bit) */
71 /**** FAT12/16 specific *****/
72 int bs_drvnum; /* Drive number */
73 int bs_bootsig; /* Is 0x29 if the following 3 fields are valid */
74 unsigned int bs_volid; /* Volume ID */
75 char bs_vollab[12]; /* Volume label, 11 chars plus \0 */
76 char bs_filsystype[9]; /* File system type, 8 chars plus \0 */
77
78 /**** FAT32 specific *****/
79 int bpb_fatsz32;
80
81 int last_word; /* Must be 0xaa55 */
82
83 int fat_type; /* What type of FAT is this? */
84};
85
86#define FAT_ATTR_READ_ONLY 0x01
87#define FAT_ATTR_HIDDEN 0x02
88#define FAT_ATTR_SYSTEM 0x04
89#define FAT_ATTR_VOLUME_ID 0x08
90#define FAT_ATTR_DIRECTORY 0x10
91#define FAT_ATTR_ARCHIVE 0x20
92#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
93 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
94
95
96#define FATDIR_NAME 0
97#define FATDIR_ATTR 11
98#define FATDIR_NTRES 12
99#define FATDIR_CRTTIMETENTH 13
100#define FATDIR_CRTTIME 14
101#define FATDIR_CRTDATE 16
102#define FATDIR_LSTACCDATE 18
103#define FATDIR_FSTCLUSHI 20
104#define FATDIR_WRTTIME 22
105#define FATDIR_WRTDATE 24
106#define FATDIR_FSTCLUSLO 26
107#define FATDIR_FILESIZE 28
108
109struct fat_direntry
110{
111 unsigned char name[12]; /* Name plus \0 */
112 unsigned short attr; /* Attributes */
113 unsigned char crttimetenth; /* Millisecond creation
114 time stamp (0-199) */
115 unsigned short crttime; /* Creation time */
116 unsigned short crtdate; /* Creation date */
117 unsigned short lstaccdate; /* Last access date */
118 unsigned short fstclushi; /* High word of first cluster
119 (0 for FAT12/16) */
120 unsigned short wrttime; /* Last write time */
121 unsigned short wrtdate; /* Last write date */
122 unsigned short fstcluslo; /* Low word of first cluster */
123 unsigned int filesize; /* File size in bytes */
124};
125
126struct fat_context
127{
128 unsigned int curr_dir_sec; /* Current directory sector */
129
130};
131
132struct disk_info
133{
134 int num_sectors;
135 int sec_per_track;
136 int num_heads;
137 unsigned int hidden_sectors;
138};
139
140struct fat_dirent
141{
142 int entry;
143 unsigned int cached_sec;
144 unsigned int num_sec;
145 char cached_buf[BLOCK_SIZE];
146};
147
148int fat_format(struct disk_info *di, char *vol_name);
149int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name);
150int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir);
151int fat_getnext(struct bpb *bpb, struct fat_dirent *ent,
152 struct fat_direntry *entry);
153
154#endif
diff --git a/firmware/drivers/i2c.c b/firmware/drivers/i2c.c
new file mode 100644
index 0000000000..3a5603ddd4
--- /dev/null
+++ b/firmware/drivers/i2c.c
@@ -0,0 +1,212 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "lcd.h"
20#include "sh7034.h"
21#include "debug.h"
22
23#define PB13 0x2000
24#define PB7 0x0080
25#define PB5 0x0020
26
27/* cute little functions */
28#define SDA_LO (PBDR &= ~PB7)
29#define SDA_HI (PBDR |= PB7)
30#define SDA_INPUT (PBIOR &= ~PB7)
31#define SDA_OUTPUT (PBIOR |= PB7)
32#define SDA (PBDR & PB7)
33
34#define SCL_INPUT (PBIOR &= ~PB13)
35#define SCL_OUTPUT (PBIOR |= PB13)
36#define SCL_LO (PBDR &= ~PB13)
37#define SCL_HI (PBDR |= PB13)
38#define SCL (PBDR & PB13)
39
40/* arbitrary delay loop */
41#define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0)
42
43void i2c_start(void)
44{
45 SDA_OUTPUT;
46 SDA_HI;
47 SCL_HI;
48 SDA_LO;
49 DELAY;
50 SCL_LO;
51}
52
53void i2c_stop(void)
54{
55 SDA_LO;
56 SCL_HI;
57 DELAY;
58 SDA_HI;
59}
60
61void i2c_init(void)
62{
63 int i;
64
65 /* make PB5, PB7 & PB13 general I/O */
66 PBCR1 &= ~0x0c00; /* PB13 */
67 PBCR2 &= ~0xcc00; /* PB5 abd PB7 */
68
69 /* PB5 is "MAS enable". make it output and high */
70 PBIOR |= PB5;
71 PBDR |= PB5;
72
73 /* Set the clock line to an output */
74 PBIOR |= PB13;
75
76 SDA_OUTPUT;
77 SDA_HI;
78 SCL_LO;
79 for (i=0;i<3;i++)
80 i2c_stop();
81}
82
83void i2c_ack(int bit)
84{
85 /* Here's the deal. The MAS is slow, and sometimes needs to wait
86 before it can receive the acknowledge. Therefore it forces the clock
87 low until it is ready. We need to poll the clock line until it goes
88 high before we release the ack. */
89
90 SCL_LO; /* Set the clock low */
91 if ( bit )
92 SDA_HI;
93 else
94 SDA_LO;
95
96 SCL_INPUT; /* Set the clock to input */
97 while(!SCL); /* and wait for the MAS to release it */
98
99 DELAY;
100 SCL_OUTPUT;
101 SCL_LO;
102}
103
104int i2c_getack(void)
105{
106 unsigned short x;
107
108 /* Here's the deal. The MAS is slow, and sometimes needs to wait
109 before it can send the acknowledge. Therefore it forces the clock
110 low until it is ready. We need to poll the clock line until it goes
111 high before we read the ack. */
112
113 SDA_LO; /* First, discharge the data line */
114 SDA_INPUT; /* And set to input */
115 SCL_LO; /* Set the clock low */
116 SCL_INPUT; /* Set the clock to input */
117 while(!SCL); /* and wait for the MAS to release it */
118
119 x = SDA;
120 if (x)
121 /* ack failed */
122 return 0;
123 SCL_OUTPUT;
124 SCL_LO;
125 SDA_HI;
126 SDA_OUTPUT;
127 return 1;
128}
129
130void i2c_outb(unsigned char byte)
131{
132 int i;
133
134 /* clock out each bit, MSB first */
135 for ( i=0x80; i; i>>=1 ) {
136 if ( i & byte )
137 SDA_HI;
138 else
139 SDA_LO;
140 SCL_HI;
141 SCL_LO;
142 }
143
144 SDA_HI;
145}
146
147unsigned char i2c_inb(int ack)
148{
149 int i;
150 unsigned char byte = 0;
151
152 /* clock in each bit, MSB first */
153 for ( i=0x80; i; i>>=1 ) {
154 /* Tricky business. Here we discharge the data line by driving it low
155 and then set it to input to see if it stays low or goes high */
156 SDA_LO; /* First, discharge the data line */
157 SDA_INPUT; /* And set to input */
158 SCL_HI;
159 if ( SDA )
160 byte |= i;
161 SCL_LO;
162 SDA_OUTPUT;
163 }
164
165 i2c_ack(ack);
166
167 return byte;
168}
169
170int i2c_write(int address, unsigned char* buf, int count )
171{
172 int i,x=0;
173
174 i2c_start();
175 i2c_outb(address & 0xfe);
176 if (i2c_getack())
177 {
178 for (i=0; i<count; i++)
179 {
180 i2c_outb(buf[i]);
181 if (!i2c_getack())
182 {
183 x=-2;
184 break;
185 }
186 }
187 }
188 else
189 {
190 debugf("i2c_write() - no ack\n");
191 x=-1;
192 }
193 i2c_stop();
194 return x;
195}
196
197int i2c_read(int address, unsigned char* buf, int count )
198{
199 int i,x=0;
200
201 i2c_start();
202 i2c_outb(address | 1);
203 if (i2c_getack()) {
204 for (i=0; i<count; i++) {
205 buf[i] = i2c_inb(0);
206 }
207 }
208 else
209 x=-1;
210 i2c_stop();
211 return x;
212}
diff --git a/firmware/drivers/i2c.h b/firmware/drivers/i2c.h
new file mode 100644
index 0000000000..a16077428c
--- /dev/null
+++ b/firmware/drivers/i2c.h
@@ -0,0 +1,33 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef I2C_H
20#define I2C_H
21
22extern void i2c_init(void);
23extern int i2c_write(int device, unsigned char* buf, int count );
24extern int i2c_read(int device, unsigned char* buf, int count );
25extern int i2c_readmem(int device, int address, unsigned char* buf, int count );
26extern void i2c_outb(unsigned char byte);
27extern unsigned char i2c_inb(int ack);
28extern void i2c_start(void);
29extern void i2c_stop(void);
30extern void i2c_ack(int bit);
31extern int i2c_getack(void);
32
33#endif
diff --git a/firmware/drivers/lcd.c b/firmware/drivers/lcd.c
new file mode 100644
index 0000000000..737bf92a6b
--- /dev/null
+++ b/firmware/drivers/lcd.c
@@ -0,0 +1,680 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "config.h"
21#include "lcd.h"
22
23#ifndef SIMULATOR
24/*
25 * About /CS,DS,SC,SD
26 * ------------------
27 *
28 * LCD on JBP and JBR uses a SPI protocol to receive orders (SDA and SCK lines)
29 *
30 * - /CS -> Chip Selection line :
31 * 0 : LCD chipset is activated.
32 * - DS -> Data Selection line, latched at the rising edge
33 * of the 8th serial clock (*) :
34 * 0 : instruction register,
35 * 1 : data register;
36 * - SC -> Serial Clock line (SDA).
37 * - SD -> Serial Data line (SCK), latched at the rising edge
38 * of each serial clock (*).
39 *
40 * _ _
41 * /CS \ /
42 * \______________________________________________________/
43 * _____ ____ ____ ____ ____ ____ ____ ____ ____ _____
44 * SD \/ D7 \/ D6 \/ D5 \/ D4 \/ D3 \/ D2 \/ D1 \/ D0 \/
45 * _____/\____/\____/\____/\____/\____/\____/\____/\____/\_____
46 *
47 * _____ _ _ _ _ _ _ _ ________
48 * SC \ * \ * \ * \ * \ * \ * \ * \ *
49 * \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
50 * _ _________________________________________________________
51 * DS \/
52 * _/\_________________________________________________________
53 *
54 */
55
56/*
57 * The only way to do logical operations in an atomic way
58 * on SH1 is using :
59 *
60 * or.b/and.b/tst.b/xor.b #imm,@(r0,gbr)
61 *
62 * but GCC doesn't generate them at all so some assembly
63 * codes are needed here.
64 *
65 * The Global Base Register gbr is expected to be zero
66 * and r0 is the address of one register in the on-chip
67 * peripheral module.
68 *
69 */
70
71 /*
72 * Enter a LCD session :
73 *
74 * QI(LCDR) &= ~(LCD_CS|LCD_DS|LCD_SD|LCD_SC);
75 */
76static void lcd_start (void)
77{
78 asm
79 ("and.b\t%0,@(r0,gbr)"
80 :
81 : /* %0 */ "I"(~(LCD_CS|LCD_DS|LCD_SD|LCD_SC)),
82 /* %1 */ "z"(LCDR));
83}
84
85 /*
86 * Leave a LCD session :
87 *
88 * QI(LCDR) |= LCD_CS|LCD_RS|LCD_SD|LCD_SC;
89 */
90static void lcd_stop (void)
91{
92 asm
93 ("or.b\t%0,@(r0,gbr)"
94 :
95 : /* %0 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC),
96 /* %1 */ "z"(LCDR));
97}
98
99static void lcd_byte (int byte,int rs)
100 /*
101 * char j = 0x80;
102 * if (rs)
103 * do
104 * {
105 * QI(LCDR) &= ~(LCD_SC|LCD_SD);
106 * if (j & byte)
107 * QI(LCDR) |= LCD_SD;
108 * QI(LCDR) |= LCD_SC|LCD_DS;
109 * }
110 * while ((unsigned char)j >>= 1);
111 * else
112 * do
113 * {
114 * QI(LCDR) &= ~(LCD_SC|LCD_SD|LCD_DS);
115 * if (j & byte)
116 * QI(LCDR) |= LCD_SD;
117 * QI(LCDR) |= LCD_SC;
118 * }
119 * while ((unsigned char)j >>= 1);
120 */
121{
122 if (rs > 0)
123 asm
124 ("shll8\t%0\n"
125 "0:\n\t"
126 "and.b\t%2,@(r0,gbr)\n\t"
127 "shll\t%0\n\t"
128 "bf\t1f\n\t"
129 "or.b\t%3,@(r0,gbr)\n"
130 "1:\n\t"
131 "or.b\t%4,@(r0,gbr)\n"
132 "add\t#-1,%1\n\t"
133 "cmp/pl\t%1\n\t"
134 "bt\t0b"
135 :
136 : /* %0 */ "r"(((unsigned)byte)<<16),
137 /* %1 */ "r"(8),
138 /* %2 */ "I"(~(LCD_SC|LCD_SD)),
139 /* %3 */ "I"(LCD_SD),
140 /* %4 */ "I"(LCD_SC|LCD_DS),
141 /* %5 */ "z"(LCDR));
142 else
143 asm
144 ("shll8\t%0\n"
145 "0:\n\t"
146 "and.b\t%2,@(r0,gbr)\n\t"
147 "shll\t%0\n\t"
148 "bf\t1f\n\t"
149 "or.b\t%3,@(r0,gbr)\n"
150 "1:\n\t"
151 "or.b\t%4,@(r0,gbr)\n"
152 "add\t#-1,%1\n\t"
153 "cmp/pl\t%1\n\t"
154 "bt\t0b"
155 :
156 : /* %0 */ "r"(((unsigned)byte)<<16),
157 /* %1 */ "r"(8),
158 /* %2 */ "I"(~(LCD_SC|LCD_DS|LCD_SD)),
159 /* %3 */ "I"(LCD_SD),
160 /* %4 */ "I"(LCD_SC),
161 /* %5 */ "z"(LCDR));
162}
163
164void lcd_data (int data)
165{
166 lcd_byte (data,1);
167}
168
169void lcd_instruction (int instruction)
170{
171 lcd_byte (instruction,0);
172}
173
174void lcd_zero (int length)
175{
176 length *= 8;
177 while (--length >= 0)
178 lcd_data (0);
179}
180
181void lcd_fill (int data,int length)
182{
183 length *= 8;
184 while (--length >= 0)
185 lcd_data (data);
186}
187
188void lcd_copy (void *data,int count)
189{
190 while (--count >= 0)
191 lcd_data (*((char *)data)++);
192}
193
194static void lcd_goto (int x,int y)
195{
196 lcd_instruction (LCD_CURSOR(x,y));
197}
198
199/*** BACKLIGHT ***/
200
201static void lcd_toggle_backlight (void)
202{
203 PAIOR ^= LCD_BL;
204}
205
206static void lcd_turn_on_backlight (void)
207{
208 PAIOR |= LCD_BL;
209}
210
211static void lcd_turn_off_backlight (void)
212{
213 PAIOR &= ~LCD_BL;
214}
215
216/*** ICONS ***/
217#endif
218
219#ifdef HAVE_LCD_CHARCELLS
220# ifndef JBP_OLD
221
222static char const lcd_ascii[] =
223{
224/*****************************************************************************************/
225/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
226/* ************************************************************************************/
227/* 0x */ 0x00,0x01,0x02,0x03,0x00,0x00,0x00,0x00,0x04,0x05,0x00,0x00,0x00,0x00,0x00,0x00,
228/* 1x */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
229/* 2x */ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
230/* 3x */ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
231/* 4x */ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
232/* 5x */ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
233/* 6x */ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
234/* 7x */ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x20,0x20,0x20,0x20,0x20,
235/* 8x */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
236/* 9x */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
237/* Ax */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
238/* Bx */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
239/* Cx */ 0x41,0x41,0x41,0x41,0x41,0x41,0x20,0x43,0x45,0x45,0x45,0x45,0x49,0x49,0x49,0x49,
240/* Dx */ 0x44,0x4E,0x4F,0x4F,0x4F,0x4F,0x4F,0x20,0x20,0x55,0x55,0x55,0x55,0x59,0x20,0x20,
241/* Ex */ 0x61,0x61,0x61,0x61,0x61,0x61,0x20,0x63,0x65,0x65,0x65,0x65,0x69,0x69,0x69,0x69,
242/* Fx */ 0x64,0x6E,0x6F,0x6F,0x6F,0x6F,0x6F,0x20,0x20,0x75,0x75,0x75,0x75,0x79,0x79,0x79
243/******/
244 };
245
246# else
247
248static char const lcd_ascii[] =
249 {
250/*****************************************************************************************/
251/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
252/* ************************************************************************************/
253/* 0x */ 0x00,0x01,0x02,0x03,0x00,0x00,0x00,0x00,0x85,0x89,0x00,0x00,0x00,0x00,0x00,0x00,
254/* 1x */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
255/* 2x */ 0x24,0x25,0x26,0x37,0x06,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,
256/* 3x */ 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,
257/* 4x */ 0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,
258/* 5x */ 0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0xA9,0x33,0xCE,0x00,0x15,
259/* 6x */ 0x00,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,
260/* 7x */ 0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x24,0x24,0x24,0x24,0x24,
261/* 8x */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
262/* 9x */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
263/* Ax */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
264/* Bx */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
265/* Cx */ 0x45,0x45,0x45,0x45,0x45,0x45,0x24,0x47,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,
266/* Dx */ 0x48,0x52,0x53,0x53,0x53,0x53,0x53,0x24,0x24,0x59,0x59,0x59,0x59,0x5D,0x24,0x24,
267/* Ex */ 0x65,0x65,0x65,0x65,0x65,0x65,0x24,0x67,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,
268/* Fx */ 0x73,0x72,0x73,0x73,0x73,0x73,0x73,0x24,0x24,0x79,0x79,0x79,0x79,0x7D,0x24,0x7D
269/******/
270 };
271
272# endif
273
274void lcd_puts (char const *string)
275{
276 while (*string)
277 lcd_data (LCD_ASCII(*string++));
278}
279
280void lcd_putns (char const *string,int n)
281{
282 while (n--)
283 lcd_data (LCD_ASCII(*string++));
284}
285
286void lcd_putc (int character)
287{
288 lcd_data (LCD_ASCII(character));
289}
290
291void lcd_pattern (int which,char const *pattern,int count)
292{
293 lcd_instruction (LCD_PRAM|which);
294 lcd_copy ((void *)pattern,count);
295}
296
297void lcd_puthex (unsigned int value,int digits)
298{
299 switch (digits) {
300 case 8:
301 lcd_puthex (value >> 16,4);
302 case 4:
303 lcd_puthex (value >> 8,2);
304 case 2:
305 lcd_puthex (value >> 4,1);
306 case 1:
307 value &= 15;
308 lcd_putc (value+((value < 10) ? '0' : ('A'-10)));
309 }
310}
311
312
313/* HAVE_LCD_CHARCELLS */
314#elif defined(HAVE_LCD_BITMAP)
315
316/*
317 * All bitmaps have this format:
318 * Bits within a byte are arranged veritcally, LSB at top.
319 * Bytes are stored in column-major format, with byte 0 at top left,
320 * byte 1 is 2nd from top, etc. Bytes following left-most column
321 * starts 2nd left column, etc.
322 *
323 * Note: The HW takes bitmap bytes in row-major order.
324 *
325 * Memory copy of display bitmap
326 */
327unsigned char display[DISP_X][DISP_Y/8];
328
329/*
330 * ASCII character generation tables
331 *
332 * This contains only the printable characters (0x20-0x7f).
333 * Each element in this table is a character pattern bitmap.
334 */
335#define ASCII_MIN 0x20 /* First char in table */
336#define ASCII_MAX 0x7f /* Last char in table */
337
338extern const unsigned char char_gen_6x8[][5][1];
339extern const unsigned char char_gen_8x12[][7][2];
340extern const unsigned char char_gen_12x16[][11][2];
341
342
343/* All zeros and ones bitmaps for area filling */
344static const unsigned char zeros[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00 };
346static const unsigned char ones[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
347 0xff, 0xff };
348
349static int lcd_y; /* Current pixel row */
350static int lcd_x; /* Current pixel column */
351static int lcd_size; /* Current font width */
352
353#ifndef SIMULATOR
354
355/*
356 * Initialize LCD
357 */
358void lcd_init (void)
359{
360 /* Initialize PB0-3 as output pins */
361 PBCR2 &= 0xff00; /* MD = 00 */
362 PBIOR |= 0x000f; /* IOR = 1 */
363
364 /* Initialize LCD */
365 lcd_write (TRUE, LCD_CNTL_RESET);
366 lcd_write (TRUE, LCD_CNTL_POWER);
367 lcd_write (TRUE, LCD_CNTL_SEGREMAP);
368 lcd_write (TRUE, LCD_CNTL_OUTSCAN);
369 lcd_write (TRUE, LCD_CNTL_CONTRAST);
370 lcd_write (TRUE, 0x30); /* Contrast parameter */
371 lcd_write (TRUE, LCD_CNTL_DISPON);
372
373 lcd_clear_display();
374 lcd_update();
375}
376
377/*
378 * Update the display.
379 * This must be called after all other LCD funtions that change the display.
380 */
381void lcd_update (void)
382{
383 int x, y;
384
385 /* Copy display bitmap to hardware */
386 for (y = 0; y < DISP_Y/8; y++)
387 {
388 lcd_write (TRUE, LCD_CNTL_PAGE | (y & 0xf));
389 lcd_write (TRUE, LCD_CNTL_HIGHCOL);
390 lcd_write (TRUE, LCD_CNTL_LOWCOL);
391
392 for (x = 0; x < DISP_X; x++)
393 lcd_write (FALSE, display[x][y]);
394 }
395}
396
397static void lcd_write (bool command, int value)
398{
399 int bit;
400
401 /* Enable chip select, set DC if data */
402 PBDR &= ~(PBDR_LCD_CS1|PBDR_LCD_DC);
403 if (!command)
404 PBDR |= PBDR_LCD_DC;
405
406 /* Send each bit, starting with MSB */
407 for (bit = 0x80; bit > 0; bit >>= 1)
408 {
409 PBDR &= ~(PBDR_LCD_SDA|PBDR_LCD_SCK);
410 if (value & bit)
411 PBDR |= PBDR_LCD_SDA;
412 PBDR |= PBDR_LCD_SCK;
413 }
414
415 /* Disable chip select */
416 PBDR |= PBDR_LCD_CS1;
417}
418
419#endif /* SIMULATOR */
420
421/*
422 * Clear the display
423 */
424void lcd_clear_display (void)
425{
426 lcd_position (0, 0, 8);
427 memset (display, 0, sizeof display);
428}
429
430/*
431 * Set current x,y position and font size
432 */
433void lcd_position (int x, int y, int size)
434{
435 if (x >= 0 && x < DISP_X && y >= 0 && y < DISP_Y)
436 {
437 lcd_x = x;
438 lcd_y = y;
439 }
440
441 lcd_size = size;
442}
443
444/*
445 * Display a string at current position and size
446 */
447void lcd_string (const char *str)
448{
449 int x = lcd_x;
450 int nx = lcd_size;
451 int ny, ch;
452 const unsigned char *src;
453
454 if (nx == 12)
455 ny = 16;
456 else if (nx == 8)
457 ny = 12;
458 else
459 {
460 nx = 6;
461 ny = 8;
462 }
463
464 while ((ch = *str++) != '\0')
465 {
466 if (ch == '\n' || lcd_x + nx > DISP_X)
467 {
468 /* Wrap to next line */
469 lcd_x = x;
470 lcd_y += ny;
471 }
472
473 if (lcd_y + ny > DISP_Y)
474 return;
475
476 /* Limit to char generation table */
477 if (ch >= ASCII_MIN && ch <= ASCII_MAX)
478 {
479 if (nx == 12)
480 src = char_gen_12x16[ch-ASCII_MIN][0];
481 else if (nx == 8)
482 src = char_gen_8x12[ch-ASCII_MIN][0];
483 else
484 src = char_gen_6x8[ch-ASCII_MIN][0];
485
486 lcd_bitmap (src, lcd_x, lcd_y, nx-1, ny, TRUE);
487 lcd_bitmap (zeros, lcd_x+nx-1, lcd_y, 1, ny, TRUE);
488
489 lcd_x += nx;
490 }
491 }
492}
493
494/*
495 * Display a bitmap at (x, y), size (nx, ny)
496 * clear is TRUE to clear destination area first
497 */
498void lcd_bitmap (const unsigned char *src, int x, int y, int nx, int ny,
499 bool clear)
500{
501 unsigned char *dst;
502 unsigned char *dst2 = &display[x][y/8];
503 unsigned int data, mask, mask2, mask3, mask4;
504 int shift = y & 7;
505
506 ny += shift;
507
508 /* Calculate bit masks */
509 mask4 = ~(0xfe << ((ny-1) & 7));
510 if (clear)
511 {
512 mask = ~(0xff << shift);
513 mask2 = 0;
514 mask3 = ~mask4;
515 if (ny <= 8)
516 mask3 |= mask;
517 }
518 else
519 mask = mask2 = mask3 = 0xff;
520
521 /* Loop for each column */
522 for (x = 0; x < nx; x++)
523 {
524 dst = dst2;
525 dst2 += DISP_Y/8;
526 data = 0;
527 y = 0;
528
529 if (ny > 8)
530 {
531 /* First partial row */
532 data = *src++ << shift;
533 *dst = (*dst & mask) ^ data;
534 data >>= 8;
535 dst++;
536
537 /* Intermediate rows */
538 for (y = 8; y < ny-8; y += 8)
539 {
540 data |= *src++ << shift;
541 *dst = (*dst & mask2) ^ data;
542 data >>= 8;
543 dst++;
544 }
545 }
546
547 /* Last partial row */
548 if (y + shift < ny)
549 data |= *src++ << shift;
550 *dst = (*dst & mask3) ^ (data & mask4);
551 }
552}
553
554/*
555 * Clear a rectangular area at (x, y), size (nx, ny)
556 */
557void lcd_clearrect (int x, int y, int nx, int ny)
558{
559 int i;
560 for (i = 0; i < nx; i++)
561 lcd_bitmap (zeros, x+i, y, 1, ny, TRUE);
562}
563
564/*
565 * Fill a rectangular area at (x, y), size (nx, ny)
566 */
567void lcd_fillrect (int x, int y, int nx, int ny)
568{
569 int i;
570 for (i = 0; i < nx; i++)
571 lcd_bitmap (ones, x+i, y, 1, ny, TRUE);
572}
573
574/* Invert a rectangular area at (x, y), size (nx, ny) */
575void lcd_invertrect (int x, int y, int nx, int ny)
576{
577 int i;
578 for (i = 0; i < nx; i++)
579 lcd_bitmap (ones, x+i, y, 1, ny, FALSE);
580}
581
582#define DRAW_PIXEL(x,y) display[x][y/8] |= (1<<(y&7))
583#define CLEAR_PIXEL(x,y) display[x][y/8] &= ~(1<<(y&7))
584
585void lcd_drawline( int x1, int y1, int x2, int y2 )
586{
587 int numpixels;
588 int i;
589 int deltax, deltay;
590 int d, dinc1, dinc2;
591 int x, xinc1, xinc2;
592 int y, yinc1, yinc2;
593
594 deltax = abs(x2 - x1);
595 deltay = abs(y2 - y1);
596
597 if(deltax >= deltay)
598 {
599 numpixels = deltax;
600 d = 2 * deltay - deltax;
601 dinc1 = deltay * 2;
602 dinc2 = (deltay - deltax) * 2;
603 xinc1 = 1;
604 xinc2 = 1;
605 yinc1 = 0;
606 yinc2 = 1;
607 }
608 else
609 {
610 numpixels = deltay;
611 d = 2 * deltax - deltay;
612 dinc1 = deltax * 2;
613 dinc2 = (deltax - deltay) * 2;
614 xinc1 = 0;
615 xinc2 = 1;
616 yinc1 = 1;
617 yinc2 = 1;
618 }
619 numpixels++; /* include endpoints */
620
621 if(x1 > x2)
622 {
623 xinc1 = -xinc1;
624 xinc2 = -xinc2;
625 }
626
627 if(y1 > y2)
628 {
629 yinc1 = -yinc1;
630 yinc2 = -yinc2;
631 }
632
633 x = x1;
634 y = y1;
635
636 for(i=0; i<numpixels; i++)
637 {
638 DRAW_PIXEL(x,y);
639
640 if(d < 0)
641 {
642 d += dinc1;
643 x += xinc1;
644 y += yinc1;
645 }
646 else
647 {
648 d += dinc2;
649 x += xinc2;
650 y += yinc2;
651 }
652 }
653}
654
655/*
656 * Set a single pixel
657 */
658void lcd_drawpixel(int x, int y)
659{
660 DRAW_PIXEL(x,y);
661}
662
663/*
664 * Clear a single pixel
665 */
666void lcd_clearpixel(int x, int y)
667{
668 CLEAR_PIXEL(x,y);
669}
670
671
672#else
673/* no LCD defined, no code to use */
674#endif
675
676/* -----------------------------------------------------------------
677 * local variables:
678 * eval: (load-file "rockbox-mode.el")
679 * end:
680 */
diff --git a/firmware/drivers/lcd.h b/firmware/drivers/lcd.h
new file mode 100644
index 0000000000..dcfa1d587e
--- /dev/null
+++ b/firmware/drivers/lcd.h
@@ -0,0 +1,162 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef __LCD_H__
21#define __LCD_H__
22
23#include "sh7034.h"
24#include "types.h"
25#include "config.h"
26
27#define LCDR (PBDR+1)
28
29/* PA14 : /LCD-BL --- backlight */
30#define LCD_BL (14-8)
31
32#ifdef HAVE_LCD_CHARCELLS
33 /* JukeBox MP3 Player - AJB6K, AJBS20 */
34# define LCD_DS +1 // PB0 = 1 --- 0001 --- LCD-DS
35# define LCD_CS +2 // PB1 = 1 --- 0010 --- /LCD-CS
36# define LCD_SD +4 // PB2 = 1 --- 0100 --- LCD-SD
37# define LCD_SC +8 // PB3 = 1 --- 1000 --- LCD-SC
38# ifndef JBP_OLD
39# define LCD_CONTRAST_SET ((char)0x50)
40# define LCD_CRAM ((char)0x80) /* Characters */
41# define LCD_PRAM ((char)0xC0) /* Patterns */
42# define LCD_IRAM ((char)0x40) /* Icons */
43# else
44# define LCD_CONTRAST_SET ((char)0xA8)
45# define LCD_CRAM ((char)0xB0) /* Characters */
46# define LCD_PRAM ((char)0x80) /* Patterns */
47# define LCD_IRAM ((char)0xE0) /* Icons */
48# endif
49# define LCD_ASCII(c) (lcd_ascii[(c)&255])
50# define LCD_CURSOR(x,y) ((char)(LCD_CRAM+((y)*16+(x))))
51# define LCD_ICON(i) ((char)(LCD_IRAM+i))
52# define LCD_ICON_BATTERY 0
53# define LCD_BATTERY_FRAME 0x02
54# define LCD_BATTERY_BAR1 0x08
55# define LCD_BATTERY_BAR2 0x04
56# define LCD_BATTERY_BAR3 0x10
57# define LCD_ICON_USB 2
58# define LCD_USB_LOGO 0xFF
59# define LCD_ICON_PLAY 3
60# define LCD_PLAY_ICON 0xFF
61# define LCD_ICON_RECORD 4
62# define LCD_RECORD_ICON 0x10
63# define LCD_ICON_STOP 5
64# define LCD_STOP_ICON 0x0F
65# define LCD_ICON_AUDIO 5
66# define LCD_AUDIO_ICON 0xF0
67# define LCD_ICON_REVERSE 6
68# define LCD_REVERSE_ICON 0xFF
69# define LCD_ICON_SINGLE 7
70# define LCD_SINGLE_ICON 0xFF
71# define LCD_ICON_VOLUME0 9
72# define LCD_VOLUME_ICON 0x04
73# define LCD_VOLUME_BAR1 0x02
74# define LCD_VOLUME_BAR2 0x01
75# define LCD_ICON_VOLUME1 10
76# define LCD_VOLUME_BAR3 0x08
77# define LCD_VOLUME_BAR4 0x04
78# define LCD_VOLUME_BAR5 0x01
79# define LCD_ICON_PARAM 10
80# define LCD_PARAM_SYMBOL 0xF0
81#endif
82
83#ifdef HAVE_LCD_BITMAP
84/* JukeBox MP3 Recorder - AJBR --- FIXME */
85
86/* Defines from Alan on IRC, April 11th 2002 */
87#define LCD_SD +1 // PB0 = 1 --- 0001
88#define LCD_SC +2 // PB1 = 1 --- 0010
89#define LCD_RS +4 // PB2 = 1 --- 0100
90#define LCD_CS +8 // PB3 = 1 --- 1000
91
92#define LCD_DS LCD_RS
93
94#define LCD_SET_LOWER_COLUMN_ADDRESS ((char)0x00)
95#define LCD_SET_HIGHER_COLUMN_ADDRESS ((char)0x10)
96#define LCD_SET_INTERNAL_REGULATOR_RESISTOR_RATIO ((char)0x20)
97#define LCD_SET_POWER_CONTROL_REGISTER ((char)0x28)
98#define LCD_SET_DISPLAY_START_LINE ((char)0x40)
99#define LCD_SET_CONTRAST_CONTROL_REGISTER ((char)0x81)
100#define LCD_SET_SEGMENT_REMAP ((char)0xA0)
101#define LCD_SET_LCD_BIAS ((char)0xA2)
102#define LCD_SET_ENTIRE_DISPLAY_OFF ((char)0xA4)
103#define LCD_SET_ENTIRE_DISPLAY_ON ((char)0xA5)
104#define LCD_SET_NORMAL_DISPLAY ((char)0xA6)
105#define LCD_SET_REVERSE_DISPLAY ((char)0xA7)
106#define LCD_SET_INDICATOR_OFF ((char)0xAC)
107#define LCD_SET_INDICATOR_ON ((char)0xAD)
108#define LCD_SET_DISPLAY_OFF ((char)0xAE)
109#define LCD_SET_DISPLAY_ON ((char)0xAF)
110#define LCD_SET_PAGE_ADDRESS ((char)0xB0)
111#define LCD_SET_COM_OUTPUT_SCAN_DIRECTION ((char)0xC0)
112#define LCD_SET_DISPLAY_OFFSET ((char)0xD3)
113#define LCD_SET_READ_MODIFY_WRITE_MODE ((char)0xE0)
114#define LCD_SOFTWARE_RESET ((char)0xE2)
115#define LCD_NOP ((char)0xE3)
116#define LCD_SET_END_OF_READ_MODIFY_WRITE_MODE ((char)0xEE)
117
118
119#define DISP_X 112
120#define DISP_Y 64
121
122#define LCD_WIDTH DISP_X /* Display width in pixels */
123#define LCD_HEIGHT DISP_Y /* Display height in pixels */
124
125void lcd_init (void);
126void lcd_update (void);
127void lcd_clear_display (void);
128void lcd_position (int x, int y, int size);
129void lcd_string (const char *str);
130void lcd_bitmap (const unsigned char *src, int x, int y, int nx, int ny,
131 bool clear);
132void lcd_clearrect (int x, int y, int nx, int ny);
133void lcd_fillrect (int x, int y, int nx, int ny);
134void lcd_invertrect (int x, int y, int nx, int ny);
135void lcd_drawline( int x1, int y1, int x2, int y2 );
136void lcd_drawpixel(int x, int y);
137void lcd_clearpixel(int x, int y);
138#endif
139
140
141#ifndef SIMULATOR
142
143extern void lcd_data (int data);
144extern void lcd_instruction (int instruction);
145extern void lcd_zero (int length);
146extern void lcd_fill (int data,int length);
147extern void lcd_copy (void *data,int count);
148
149#ifdef HAVE_LCD_CHARCELLS
150
151extern void lcd_puts (char const *string);
152extern void lcd_putns (char const *string,int n);
153extern void lcd_putc (int character);
154extern void lcd_puthex (unsigned int value,int digits);
155
156extern void lcd_pattern (int which,char const *pattern,int count);
157
158#endif /* HAVE_LCD_CHARCELLS */
159
160#endif /* SIMULATOR */
161
162#endif /* __LCD_H__ */
diff --git a/firmware/drivers/led.c b/firmware/drivers/led.c
new file mode 100644
index 0000000000..d01c9de612
--- /dev/null
+++ b/firmware/drivers/led.c
@@ -0,0 +1,70 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "config.h"
21
22#include <led.h>
23
24#define turn_on() \
25 set_bit (LEDB,PBDR_ADDR+1)
26
27#define turn_off() \
28 clear_bit (LEDB,PBDR_ADDR+1)
29
30#define start_timer() \
31 set_bit (2,TSTR_ADDR)
32
33#define stop_timer() \
34 clear_bit (2,TSTR_ADDR)
35
36#define eoi(subinterrupt) \
37 clear_bit (subinterrupt,TSR2_ADDR)
38
39#define set_volume(volume) \
40 GRA2 = volume & 0x7FFF
41
42
43void led_set_volume (unsigned short volume)
44{
45 volume <<= 10;
46 if (volume == 0)
47 led_turn_off ();
48 else if (volume == 0x8000)
49 led_turn_on ();
50 else
51 {
52 set_volume (volume);
53 start_timer ();
54 }
55}
56
57#pragma interrupt
58void IMIA2 (void)
59{
60 turn_off ();
61 eoi (0);
62}
63
64#pragma interrupt
65void OVI2 (void)
66{
67 turn_on ();
68 eoi (2);
69}
70
diff --git a/firmware/drivers/led.h b/firmware/drivers/led.h
new file mode 100644
index 0000000000..955c59aa81
--- /dev/null
+++ b/firmware/drivers/led.h
@@ -0,0 +1,50 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef __LED_H__
21#define __LED_H__
22
23#include <sh7034.h>
24#include <system.h>
25
26#define LEDB 6 /* PB6 : red LED */
27
28static inline void led_turn_off (void)
29{
30 clear_bit (LEDB,PBDR+1);
31 clear_bit (2,TSTR_ADDR);
32}
33
34static inline void led_turn_on (void)
35{
36 set_bit (LEDB,PBDR+1);
37 set_bit (2,TSTR_ADDR);
38}
39
40static inline void led_toggle (void)
41{
42 toggle_bit (LEDB,PBDR+1);
43}
44
45extern void led_set_volume (unsigned short volume);
46extern void led_setup (void);
47
48#endif
49
50
diff --git a/firmware/drivers/mas.c b/firmware/drivers/mas.c
new file mode 100644
index 0000000000..decfff612b
--- /dev/null
+++ b/firmware/drivers/mas.c
@@ -0,0 +1,164 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "i2c.h"
20#include "debug.h"
21#include "mas.h"
22
23/* note: 'len' is number of 32-bit words, not number of bytes! */
24int mas_readmem(int bank, int addr, unsigned long* dest, int len)
25{
26 int i;
27 unsigned char buf[16];
28
29 i=0;
30 buf[i++] = MAS_DATA_WRITE;
31 buf[i++] = bank?0xf0:0xe0;
32 buf[i++] = 0x00;
33 buf[i++] = (len & 0xff00) >> 8;
34 buf[i++] = len & 0xff;
35 buf[i++] = (addr & 0xff00) >> 8;
36 buf[i++] = addr & 0xff;
37
38 /* send read command */
39 if (i2c_write(MAS_DEV_WRITE,buf,i))
40 {
41 return -1;
42 }
43
44 return mas_devread(dest, len);
45}
46
47/* note: 'len' is number of 32-bit words, not number of bytes! */
48int mas_writemem(int bank, int addr, unsigned long* src, int len)
49{
50 int i, j;
51 unsigned char buf[60];
52 unsigned char* ptr = (unsigned char*)src;
53
54 i=0;
55 buf[i++] = MAS_DATA_WRITE;
56 buf[i++] = bank;
57 buf[i++] = 0x00;
58 buf[i++] = (len & 0xff00) >> 8;
59 buf[i++] = len & 0xff;
60 buf[i++] = (addr & 0xff00) >> 8;
61 buf[i++] = addr & 0xff;
62
63 j = 0;
64 while(len--) {
65 buf[i++] = ptr[j*4+1];
66 buf[i++] = ptr[j*4+0];
67 buf[i++] = 0;
68 buf[i++] = ptr[j*4+2];
69 j += 4;
70 }
71
72 /* send write command */
73 if (i2c_write(MAS_DEV_WRITE,buf,i))
74 {
75 return -1;
76 }
77
78 return 0;
79}
80
81int mas_readreg(int reg)
82{
83 int i;
84 unsigned char buf[16];
85
86 i=0;
87 buf[i++] = MAS_DATA_WRITE;
88 buf[i++] = 0xd0 | reg >> 4;
89 buf[i++] = (reg & 0x0f) << 4;
90
91 /* send read command */
92 if (i2c_write(MAS_DEV_WRITE,buf,i))
93 {
94 return -1;
95 }
96
97 if(mas_devread((unsigned long *)buf, 1))
98 {
99 return -2;
100 }
101
102 return buf[0] | buf[1] << 8 | buf[3] << 16;
103}
104
105int mas_writereg(int reg, unsigned short val)
106{
107 int i;
108 unsigned char buf[16];
109
110 i=0;
111 buf[i++] = MAS_DATA_WRITE;
112 buf[i++] = 0x90 | reg >> 4;
113 buf[i++] = ((reg & 0x0f) << 4) | (val & 0x0f);
114 buf[i++] = (val >> 12) & 0xff;
115 buf[i++] = (val >> 4) & 0xff;
116
117 /* send write command */
118 if (i2c_write(MAS_DEV_WRITE,buf,i))
119 {
120 return -1;
121 }
122 return 0;
123}
124
125/* note: 'len' is number of 32-bit words, not number of bytes! */
126int mas_devread(unsigned long *dest, int len)
127{
128 unsigned char* ptr = (unsigned char*)dest;
129 int ret = 0;
130 int i;
131
132 /* handle read-back */
133 i2c_start();
134 i2c_outb(MAS_DEV_WRITE);
135 if (i2c_getack()) {
136 i2c_outb(MAS_DATA_READ);
137 if (i2c_getack()) {
138 i2c_start();
139 i2c_outb(MAS_DEV_READ);
140 if (i2c_getack()) {
141 for (i=0;len;i++) {
142 len--;
143 ptr[i*4+1] = i2c_inb(0);
144 ptr[i*4+0] = i2c_inb(0);
145 ptr[i*4+3] = i2c_inb(0);
146 if(len)
147 ptr[i*4+2] = i2c_inb(0);
148 else
149 ptr[i*4+2] = i2c_inb(1); /* NAK the last byte */
150 }
151 }
152 else
153 ret = -3;
154 }
155 else
156 ret = -2;
157 }
158 else
159 ret = -1;
160
161 i2c_stop();
162
163 return ret;
164}
diff --git a/firmware/drivers/mas.h b/firmware/drivers/mas.h
new file mode 100644
index 0000000000..65e23f1498
--- /dev/null
+++ b/firmware/drivers/mas.h
@@ -0,0 +1,54 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef _MAS_H_
20#define _MAS_H_
21
22#define MAS_BANK_D0 0
23#define MAS_BANK_D1 1
24
25/*
26 MAS I2C defs
27*/
28#define MAS_ADR 0x3a
29#define MAS_DEV_WRITE (MAS_ADR | 0x00)
30#define MAS_DEV_READ (MAS_ADR | 0x01)
31
32/* registers..*/
33#define MAS_DATA_WRITE 0x68
34#define MAS_DATA_READ 0x69
35#define MAS_CONTROL 0x6a
36
37/*
38 * MAS register
39 */
40#define MAS_REG_DCCF 0x8e
41#define MAS_REG_MUTE 0xaa
42#define MAS_REG_PIODATA 0xc8
43#define MAS_REG_StartUpConfig 0xe6
44#define MAS_REG_KPRESCALE 0xe7
45#define MAS_REG_KBASS 0x6b
46#define MAS_REG_KTREBLE 0x6f
47
48int mas_readmem(int bank, int addr, unsigned long* dest, int len);
49int mas_writemem(int bank, int addr, unsigned long* src, int len);
50int mas_devread(unsigned long *buf, int len);
51int mas_readreg(int reg);
52int mas_writereg(int reg, unsigned short val);
53
54#endif
diff --git a/firmware/drivers/serial.c b/firmware/drivers/serial.c
new file mode 100644
index 0000000000..d101ab8095
--- /dev/null
+++ b/firmware/drivers/serial.c
@@ -0,0 +1,75 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "serial.h"
21
22#define TDRE 7 /* transmit data register empty */
23#define RDRF 6 /* receive data register full */
24#define ORER 5 /* overrun error */
25#define FER 4 /* frame error */
26#define PER 3 /* parity error */
27
28static int serial_byte,serial_flag;
29
30void serial_putc (char byte)
31{
32 while (!(SSR1 & (1<<TDRE)));
33 TDR1 = byte;
34 clear_bit(TDRE,SSR1_ADDR);
35}
36
37void serial_puts (char const *string)
38{
39 int byte;
40 while ((byte = *string++))
41 serial_putc (byte);
42}
43
44int serial_getc( void )
45{
46 int byte;
47 while (!serial_flag);
48 byte = serial_byte;
49 serial_flag = 0;
50 serial_putc (byte);
51 return byte;
52}
53
54void serial_setup (int baudrate)
55{
56 SCR1 = 0;
57 SSR1 = 0;
58 SMR1 = 0;
59 BRR1 = (FREQ/(32*baudrate))-1;
60 SCR1 = 0x70;
61}
62
63#pragma interrupt
64void REI1 (void)
65{
66 clear_bit (FER,SSR1_ADDR);
67}
68
69#pragma interrupt
70void RXI1 (void)
71{
72 serial_byte = RDR1;
73 serial_flag = 1;
74 clear_bit(RDRF,SSR1_ADDR);
75}
diff --git a/firmware/drivers/serial.h b/firmware/drivers/serial.h
new file mode 100644
index 0000000000..eac02e42e4
--- /dev/null
+++ b/firmware/drivers/serial.h
@@ -0,0 +1,31 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef __SERIAL_H__
21#define __SERIAL_H__
22
23#include <sh7034.h>
24#include <system.h>
25
26extern void serial_putc (char);
27extern void serial_puts (char const *);
28extern int serial_getc (void);
29extern void serial_setup (int);
30
31#endif