Commit | Line | Data |
---|---|---|
cd011f58 AW |
1 | /* Copyright (c) 2010-2011 mbed.org, MIT License\r |
2 | *\r | |
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software\r | |
4 | * and associated documentation files (the "Software"), to deal in the Software without\r | |
5 | * restriction, including without limitation the rights to use, copy, modify, merge, publish,\r | |
6 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the\r | |
7 | * Software is furnished to do so, subject to the following conditions:\r | |
8 | *\r | |
9 | * The above copyright notice and this permission notice shall be included in all copies or\r | |
10 | * substantial portions of the Software.\r | |
11 | *\r | |
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING\r | |
13 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r | |
14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r | |
15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r | |
16 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
17 | */\r | |
18 | \r | |
19 | \r | |
20 | #ifndef USBMSD_H\r | |
21 | #define USBMSD_H\r | |
22 | \r | |
23 | /* These headers are included for child class. */\r | |
24 | #include "USBEndpoints.h"\r | |
25 | #include "USBDescriptor.h"\r | |
26 | #include "USBDevice_Types.h"\r | |
27 | \r | |
28 | #include "USBDevice.h"\r | |
29 | \r | |
30 | #ifdef __GNUC__\r | |
31 | /* Packing for structs in GCC. */\r | |
32 | #define PACK_STRUCT_STRUCT __attribute__((packed))\r | |
33 | #define PACK_STRUCT_BEGIN\r | |
34 | #define PACK_STRUCT_END\r | |
35 | #else /* !__GNUC__ */\r | |
36 | /* Packing for structs in ARM compiler. */\r | |
37 | #define PACK_STRUCT_STRUCT\r | |
38 | #define PACK_STRUCT_BEGIN __packed\r | |
39 | #define PACK_STRUCT_END\r | |
40 | #endif /* __GNUC__ */\r | |
41 | \r | |
42 | /**\r | |
43 | * USBMSD class: generic class in order to use all kinds of blocks storage chip\r | |
44 | *\r | |
45 | * Introduction\r | |
46 | *\r | |
47 | * The USBMSD implements the MSD protocol. It permits to access a memory chip (flash, sdcard,...)\r | |
48 | * from a computer over USB. But this class doesn't work standalone, you need to subclass this class\r | |
49 | * and define virtual functions which are called in USBMSD.\r | |
50 | *\r | |
51 | * How to use this class with your chip ?\r | |
52 | *\r | |
53 | * You have to inherit and define some pure virtual functions (mandatory step):\r | |
54 | * - virtual int disk_read(char * data, int block): function to read a block\r | |
55 | * - virtual int disk_write(const char * data, int block): function to write a block\r | |
56 | * - virtual int disk_initialize(): function to initialize the memory\r | |
57 | * - virtual int disk_sectors(): return the number of blocks\r | |
58 | * - virtual int disk_size(): return the memory size\r | |
59 | * - virtual int disk_status(): return the status of the storage chip (0: OK, 1: not initialized, 2: no medium in the drive, 4: write protection)\r | |
60 | *\r | |
61 | * All functions names are compatible with the fat filesystem library. So you can imagine using your own class with\r | |
62 | * USBMSD and the fat filesystem library in the same program. Just be careful because there are two different parts which\r | |
63 | * will access the sd card. You can do a master/slave system using the disk_status method.\r | |
64 | *\r | |
65 | * Once these functions defined, you can call connect() (at the end of the constructor of your class for instance)\r | |
66 | * of USBMSD to connect your mass storage device. connect() will first call disk_status() to test the status of the disk.\r | |
67 | * If disk_status() returns 1 (disk not initialized), then disk_initialize() is called. After this step, connect() will collect information\r | |
68 | * such as the number of blocks and the memory size.\r | |
69 | */\r | |
70 | class USBMSD: public USBDevice {\r | |
71 | public:\r | |
72 | \r | |
73 | /**\r | |
74 | * Constructor\r | |
75 | *\r | |
76 | * @param vendor_id Your vendor_id\r | |
77 | * @param product_id Your product_id\r | |
78 | * @param product_release Your preoduct_release\r | |
79 | */\r | |
80 | USBMSD(uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001);\r | |
81 | \r | |
82 | /**\r | |
83 | * Connect the USB MSD device. Establish disk initialization before really connect the device.\r | |
84 | *\r | |
85 | * @returns true if successful\r | |
86 | */\r | |
87 | bool connect();\r | |
88 | \r | |
89 | \r | |
90 | protected:\r | |
91 | \r | |
92 | /*\r | |
93 | * read a block on a storage chip\r | |
94 | *\r | |
95 | * @param data pointer where will be stored read data\r | |
96 | * @param block block number\r | |
97 | * @returns 0 if successful\r | |
98 | */\r | |
99 | virtual int disk_read(char * data, int block) = 0;\r | |
100 | \r | |
101 | /*\r | |
102 | * write a block on a storage chip\r | |
103 | *\r | |
104 | * @param data data to write\r | |
105 | * @param block block number\r | |
106 | * @returns 0 if successful\r | |
107 | */\r | |
108 | virtual int disk_write(const char * data, int block) = 0;\r | |
109 | \r | |
110 | /*\r | |
111 | * Disk initilization\r | |
112 | */\r | |
113 | virtual int disk_initialize() = 0;\r | |
114 | \r | |
115 | /*\r | |
116 | * Return the number of blocks\r | |
117 | *\r | |
118 | * @returns number of blocks\r | |
119 | */\r | |
120 | virtual int disk_sectors() = 0;\r | |
121 | \r | |
122 | /*\r | |
123 | * Return memory size\r | |
124 | *\r | |
125 | * @returns memory size\r | |
126 | */\r | |
127 | virtual int disk_size() = 0;\r | |
128 | \r | |
129 | \r | |
130 | /*\r | |
131 | * To check the status of the storage chip\r | |
132 | *\r | |
133 | * @returns status: 0: OK, 1: disk not initialized, 2: no medium in the drive, 4: write protected\r | |
134 | */\r | |
135 | virtual int disk_status() = 0;\r | |
136 | \r | |
137 | /*\r | |
138 | * Get string product descriptor\r | |
139 | *\r | |
140 | * @returns pointer to the string product descriptor\r | |
141 | */\r | |
142 | virtual uint8_t * stringIproductDesc();\r | |
143 | \r | |
144 | /*\r | |
145 | * Get string interface descriptor\r | |
146 | *\r | |
147 | * @returns pointer to the string interface descriptor\r | |
148 | */\r | |
149 | virtual uint8_t * stringIinterfaceDesc();\r | |
150 | \r | |
151 | /*\r | |
152 | * Get configuration descriptor\r | |
153 | *\r | |
154 | * @returns pointer to the configuration descriptor\r | |
155 | */\r | |
156 | virtual uint8_t * configurationDesc();\r | |
157 | \r | |
158 | /*\r | |
159 | * Callback called when a packet is received\r | |
160 | */\r | |
161 | virtual bool EP2_OUT_callback();\r | |
162 | \r | |
163 | /*\r | |
164 | * Callback called when a packet has been sent\r | |
165 | */\r | |
166 | virtual bool EP2_IN_callback();\r | |
167 | \r | |
168 | /*\r | |
169 | * Set configuration of device. Add endpoints\r | |
170 | */\r | |
171 | virtual bool USBCallback_setConfiguration(uint8_t configuration);\r | |
172 | \r | |
173 | /*\r | |
174 | * Callback called to process class specific requests\r | |
175 | */\r | |
176 | virtual bool USBCallback_request();\r | |
177 | \r | |
178 | \r | |
179 | private:\r | |
180 | \r | |
181 | // MSC Bulk-only Stage\r | |
182 | enum Stage {\r | |
183 | READ_CBW, // wait a CBW\r | |
184 | ERROR, // error\r | |
185 | PROCESS_CBW, // process a CBW request\r | |
186 | SEND_CSW, // send a CSW\r | |
187 | WAIT_CSW, // wait that a CSW has been effectively sent\r | |
188 | };\r | |
189 | \r | |
190 | // Bulk-only CBW\r | |
191 | typedef PACK_STRUCT_BEGIN struct {\r | |
192 | uint32_t Signature;\r | |
193 | uint32_t Tag;\r | |
194 | uint32_t DataLength;\r | |
195 | uint8_t Flags;\r | |
196 | uint8_t LUN;\r | |
197 | uint8_t CBLength;\r | |
198 | uint8_t CB[16];\r | |
199 | } PACK_STRUCT_STRUCT CBW;\r | |
200 | \r | |
201 | // Bulk-only CSW\r | |
202 | typedef PACK_STRUCT_BEGIN struct {\r | |
203 | uint32_t Signature;\r | |
204 | uint32_t Tag;\r | |
205 | uint32_t DataResidue;\r | |
206 | uint8_t Status;\r | |
207 | } PACK_STRUCT_STRUCT CSW;\r | |
208 | \r | |
209 | //state of the bulk-only state machine\r | |
210 | Stage stage;\r | |
211 | \r | |
212 | // current CBW\r | |
213 | CBW cbw;\r | |
214 | \r | |
215 | // CSW which will be sent\r | |
216 | CSW csw;\r | |
217 | \r | |
218 | // addr where will be read or written data\r | |
219 | uint32_t addr;\r | |
220 | \r | |
221 | // length of a reading or writing\r | |
222 | uint32_t length;\r | |
223 | \r | |
224 | // memory OK (after a memoryVerify)\r | |
225 | bool memOK;\r | |
226 | \r | |
227 | // cache in RAM before writing in memory. Useful also to read a block.\r | |
228 | uint8_t * page;\r | |
229 | \r | |
230 | int BlockSize;\r | |
231 | int MemorySize;\r | |
232 | int BlockCount;\r | |
233 | \r | |
234 | void CBWDecode(uint8_t * buf, uint16_t size);\r | |
235 | void sendCSW (void);\r | |
236 | bool inquiryRequest (void);\r | |
237 | bool write (uint8_t * buf, uint16_t size);\r | |
238 | bool readFormatCapacity();\r | |
239 | bool readCapacity (void);\r | |
240 | bool infoTransfer (void);\r | |
241 | void memoryRead (void);\r | |
242 | bool modeSense6 (void);\r | |
243 | void testUnitReady (void);\r | |
244 | bool requestSense (void);\r | |
245 | void memoryVerify (uint8_t * buf, uint16_t size);\r | |
246 | void memoryWrite (uint8_t * buf, uint16_t size);\r | |
247 | void reset();\r | |
248 | void fail();\r | |
249 | };\r | |
250 | \r | |
251 | #endif |