Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
6
//    This file is part of emBIOS.
7
//
8
//    emBIOS is free software: you can redistribute it and/or
9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
13
//    emBIOS is distributed in the hope that it will be useful,
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
19
//    with emBIOS.  If not, see <http://www.gnu.org/licenses/>.
20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "usb/usbtarget.h"
26
#include "usb/usbdrv.h"
27
#include "nand.h"
28
 
29
 
30
int usb_target_handle_request(uint32_t* buffer, int bufsize)
31
{
32
    int size = 0;
33
    switch (buffer[0])
34
    {
35
        case 0xffff0001:  // GET NAND INFO
36
        {
37
            int banks = 1;
38
            const struct nand_device_info_type* type = nand_get_device_type(0);
39
            for (; banks < 4; banks++)
40
                if (!nand_get_device_type(banks))
41
                    break;
42
            buffer[0] = 1;
43
            buffer[1] = type->id;
44
            buffer[2] = (banks << 16) | type->pagesperblock;
45
            buffer[3] = (type->blocks << 16) | type->userblocks;
46
            size = 16;
47
            break;
48
        }
49
        case 0xffff0002:  // READ NAND PAGES
50
        case 0xffff0003:  // WRITE NAND PAGES
51
        {
52
            int banks = 1;
53
            const struct nand_device_info_type* type = nand_get_device_type(0);
54
            for (; banks < 4; banks++)
55
                if (!nand_get_device_type(banks))
56
                    break;
57
            uint32_t pagecount = banks * type->blocks * type->pagesperblock;
58
            if (buffer[2] + buffer[3] > pagecount)
59
            {
60
                buffer[0] = 0xffff0001;
61
                size = 16;
62
                break;
63
            }
64
            int i;
65
            uint32_t database = buffer[1] & ~0xc0000000;
66
            uint32_t sparebase = database + buffer[3] * 2048;
67
            uint32_t resultbase = sparebase + buffer[3] * 64;
68
            int doecc = buffer[1] & 0x80000000;
69
            int checkempty = buffer[1] & 0x40000000;
70
            for (i = 0; i < buffer[3]; i++)
71
            {
72
                int lpage = buffer[2] + i;
73
                int bank = lpage % banks;
74
                int page = (lpage / banks) % type->pagesperblock;
75
                int block = lpage / banks / type->pagesperblock;
76
                int result;
77
                if (buffer[0] == 0xffff0002)
78
                    result = nand_read_page(bank, page, (void*)(database + i * 2048),
79
                                            (void*)(sparebase + i * 64), doecc, checkempty);
80
                else if (buffer[0] == 0xffff0003)
81
                    result = nand_write_page(bank, page, (void*)(database + i * 2048),
82
                                             (void*)(sparebase + i * 64), doecc);
83
                *((int*)(resultbase + i * 4)) = result;
84
            }
85
            buffer[0] = 1;
86
            size = 16;
87
            break;
88
        }
89
        case 0xffff0004:  // ERASE NAND PAGES
90
        {
91
            int banks = 1;
92
            const struct nand_device_info_type* type = nand_get_device_type(0);
93
            for (; banks < 4; banks++)
94
                if (!nand_get_device_type(banks))
95
                    break;
96
            uint32_t blockcount = banks * type->blocks;
97
            if (buffer[2] + buffer[3] > blockcount)
98
            {
99
                buffer[0] = 0xffff0001;
100
                size = 16;
101
                break;
102
            }
103
            int i;
104
            for (i = 0; i < buffer[3]; i++)
105
            {
106
                int lblock = buffer[2] + i;
107
                int bank = lblock % banks;
108
                int block = lblock / banks;
109
                int result = nand_block_erase(bank, block * type->pagesperblock); 
110
                *((int*)(buffer[1] + i * 4)) = result;
111
            }
112
            buffer[0] = 1;
113
            size = 16;
114
            break;
115
        }
116
        default:
117
            buffer[0] = 2;
118
            size = 16;
119
    }
120
    return size;
121
}