diff options
author | huajun li <huajun.li.lee@gmail.com> | 2011-03-03 21:56:18 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-03-07 16:40:59 -0500 |
commit | 41e568d14ec0aca1b2bb19563517aad3b06d6805 (patch) | |
tree | e1c9e5a384bb0ae1909ab373b13d127ef0f0b0de /drivers/usb/storage | |
parent | 153775d94899503f5f66baaa9751a43c74d4f371 (diff) |
Staging: Merge ENE UB6250 SD card codes from keucr to drivers/usb/storage
The usb portion of this driver can now go into drivers/usb/storage.
This leaves the non-usb portion of the code still in staging.
Signed-off-by: Huajun Li <huajun.li.lee@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r-- | drivers/usb/storage/Kconfig | 14 | ||||
-rw-r--r-- | drivers/usb/storage/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/storage/ene_ub6250.c | 807 | ||||
-rw-r--r-- | drivers/usb/storage/unusual_ene_ub6250.h | 26 | ||||
-rw-r--r-- | drivers/usb/storage/usual-tables.c | 1 |
5 files changed, 850 insertions, 0 deletions
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 49a489e0371..72448bac2ee 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig | |||
@@ -198,3 +198,17 @@ config USB_LIBUSUAL | |||
198 | options libusual bias="ub" | 198 | options libusual bias="ub" |
199 | 199 | ||
200 | If unsure, say N. | 200 | If unsure, say N. |
201 | |||
202 | config USB_STORAGE_ENE_UB6250 | ||
203 | tristate "USB ENE card reader support" | ||
204 | depends on USB && SCSI | ||
205 | ---help--- | ||
206 | Say Y here if you wish to control a ENE SD Card reader. | ||
207 | To use SM/MS card, please build driver/staging/keucr/keucr.ko | ||
208 | |||
209 | This option depends on 'SCSI' support being enabled, but you | ||
210 | probably also need 'SCSI device support: SCSI disk support' | ||
211 | (BLK_DEV_SD) for most USB storage devices. | ||
212 | |||
213 | To compile this driver as a module, choose M here: the | ||
214 | module will be called ums-eneub6250. | ||
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index fcf14cdc4a0..3055d1a8010 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile | |||
@@ -25,6 +25,7 @@ endif | |||
25 | obj-$(CONFIG_USB_STORAGE_ALAUDA) += ums-alauda.o | 25 | obj-$(CONFIG_USB_STORAGE_ALAUDA) += ums-alauda.o |
26 | obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o | 26 | obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o |
27 | obj-$(CONFIG_USB_STORAGE_DATAFAB) += ums-datafab.o | 27 | obj-$(CONFIG_USB_STORAGE_DATAFAB) += ums-datafab.o |
28 | obj-$(CONFIG_USB_STORAGE_ENE_UB6250) += ums-eneub6250.o | ||
28 | obj-$(CONFIG_USB_STORAGE_FREECOM) += ums-freecom.o | 29 | obj-$(CONFIG_USB_STORAGE_FREECOM) += ums-freecom.o |
29 | obj-$(CONFIG_USB_STORAGE_ISD200) += ums-isd200.o | 30 | obj-$(CONFIG_USB_STORAGE_ISD200) += ums-isd200.o |
30 | obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += ums-jumpshot.o | 31 | obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += ums-jumpshot.o |
@@ -37,6 +38,7 @@ obj-$(CONFIG_USB_STORAGE_USBAT) += ums-usbat.o | |||
37 | ums-alauda-y := alauda.o | 38 | ums-alauda-y := alauda.o |
38 | ums-cypress-y := cypress_atacb.o | 39 | ums-cypress-y := cypress_atacb.o |
39 | ums-datafab-y := datafab.o | 40 | ums-datafab-y := datafab.o |
41 | ums-eneub6250-y := ene_ub6250.o | ||
40 | ums-freecom-y := freecom.o | 42 | ums-freecom-y := freecom.o |
41 | ums-isd200-y := isd200.o | 43 | ums-isd200-y := isd200.o |
42 | ums-jumpshot-y := jumpshot.o | 44 | ums-jumpshot-y := jumpshot.o |
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c new file mode 100644 index 00000000000..058c5d5f1c1 --- /dev/null +++ b/drivers/usb/storage/ene_ub6250.c | |||
@@ -0,0 +1,807 @@ | |||
1 | /* | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify it | ||
4 | * under the terms of the GNU General Public License as published by the | ||
5 | * Free Software Foundation; either version 2, or (at your option) any | ||
6 | * later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
16 | */ | ||
17 | #include <linux/jiffies.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <scsi/scsi.h> | ||
23 | #include <scsi/scsi_cmnd.h> | ||
24 | |||
25 | #include <linux/firmware.h> | ||
26 | |||
27 | #include "usb.h" | ||
28 | #include "transport.h" | ||
29 | #include "protocol.h" | ||
30 | #include "debug.h" | ||
31 | |||
32 | MODULE_DESCRIPTION("Driver for ENE UB6250 reader"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | |||
36 | /* | ||
37 | * The table of devices | ||
38 | */ | ||
39 | #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ | ||
40 | vendorName, productName, useProtocol, useTransport, \ | ||
41 | initFunction, flags) \ | ||
42 | { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ | ||
43 | .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } | ||
44 | |||
45 | struct usb_device_id ene_ub6250_usb_ids[] = { | ||
46 | # include "unusual_ene_ub6250.h" | ||
47 | { } /* Terminating entry */ | ||
48 | }; | ||
49 | MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids); | ||
50 | |||
51 | #undef UNUSUAL_DEV | ||
52 | |||
53 | /* | ||
54 | * The flags table | ||
55 | */ | ||
56 | #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ | ||
57 | vendor_name, product_name, use_protocol, use_transport, \ | ||
58 | init_function, Flags) \ | ||
59 | { \ | ||
60 | .vendorName = vendor_name, \ | ||
61 | .productName = product_name, \ | ||
62 | .useProtocol = use_protocol, \ | ||
63 | .useTransport = use_transport, \ | ||
64 | .initFunction = init_function, \ | ||
65 | } | ||
66 | |||
67 | static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = { | ||
68 | # include "unusual_ene_ub6250.h" | ||
69 | { } /* Terminating entry */ | ||
70 | }; | ||
71 | |||
72 | #undef UNUSUAL_DEV | ||
73 | |||
74 | |||
75 | |||
76 | /* ENE bin code len */ | ||
77 | #define ENE_BIN_CODE_LEN 0x800 | ||
78 | /* EnE HW Register */ | ||
79 | #define REG_CARD_STATUS 0xFF83 | ||
80 | #define REG_HW_TRAP1 0xFF89 | ||
81 | |||
82 | /* SRB Status */ | ||
83 | #define SS_SUCCESS 0x00 /* No Sense */ | ||
84 | #define SS_NOT_READY 0x02 | ||
85 | #define SS_MEDIUM_ERR 0x03 | ||
86 | #define SS_HW_ERR 0x04 | ||
87 | #define SS_ILLEGAL_REQUEST 0x05 | ||
88 | #define SS_UNIT_ATTENTION 0x06 | ||
89 | |||
90 | /* ENE Load FW Pattern */ | ||
91 | #define SD_INIT1_PATTERN 1 | ||
92 | #define SD_INIT2_PATTERN 2 | ||
93 | #define SD_RW_PATTERN 3 | ||
94 | #define MS_INIT_PATTERN 4 | ||
95 | #define MSP_RW_PATTERN 5 | ||
96 | #define MS_RW_PATTERN 6 | ||
97 | #define SM_INIT_PATTERN 7 | ||
98 | #define SM_RW_PATTERN 8 | ||
99 | |||
100 | #define FDIR_WRITE 0 | ||
101 | #define FDIR_READ 1 | ||
102 | |||
103 | |||
104 | struct SD_STATUS { | ||
105 | u8 Insert:1; | ||
106 | u8 Ready:1; | ||
107 | u8 MediaChange:1; | ||
108 | u8 IsMMC:1; | ||
109 | u8 HiCapacity:1; | ||
110 | u8 HiSpeed:1; | ||
111 | u8 WtP:1; | ||
112 | u8 Reserved:1; | ||
113 | }; | ||
114 | |||
115 | struct MS_STATUS { | ||
116 | u8 Insert:1; | ||
117 | u8 Ready:1; | ||
118 | u8 MediaChange:1; | ||
119 | u8 IsMSPro:1; | ||
120 | u8 IsMSPHG:1; | ||
121 | u8 Reserved1:1; | ||
122 | u8 WtP:1; | ||
123 | u8 Reserved2:1; | ||
124 | }; | ||
125 | |||
126 | struct SM_STATUS { | ||
127 | u8 Insert:1; | ||
128 | u8 Ready:1; | ||
129 | u8 MediaChange:1; | ||
130 | u8 Reserved:3; | ||
131 | u8 WtP:1; | ||
132 | u8 IsMS:1; | ||
133 | }; | ||
134 | |||
135 | |||
136 | /* SD Block Length */ | ||
137 | /* 2^9 = 512 Bytes, The HW maximum read/write data length */ | ||
138 | #define SD_BLOCK_LEN 9 | ||
139 | |||
140 | struct ene_ub6250_info { | ||
141 | /* for 6250 code */ | ||
142 | struct SD_STATUS SD_Status; | ||
143 | struct MS_STATUS MS_Status; | ||
144 | struct SM_STATUS SM_Status; | ||
145 | |||
146 | /* ----- SD Control Data ---------------- */ | ||
147 | /*SD_REGISTER SD_Regs; */ | ||
148 | u16 SD_Block_Mult; | ||
149 | u8 SD_READ_BL_LEN; | ||
150 | u16 SD_C_SIZE; | ||
151 | u8 SD_C_SIZE_MULT; | ||
152 | |||
153 | /* SD/MMC New spec. */ | ||
154 | u8 SD_SPEC_VER; | ||
155 | u8 SD_CSD_VER; | ||
156 | u8 SD20_HIGH_CAPACITY; | ||
157 | u32 HC_C_SIZE; | ||
158 | u8 MMC_SPEC_VER; | ||
159 | u8 MMC_BusWidth; | ||
160 | u8 MMC_HIGH_CAPACITY; | ||
161 | |||
162 | /*----- MS Control Data ---------------- */ | ||
163 | bool MS_SWWP; | ||
164 | u32 MSP_TotalBlock; | ||
165 | /*MS_LibControl MS_Lib;*/ | ||
166 | bool MS_IsRWPage; | ||
167 | u16 MS_Model; | ||
168 | |||
169 | /*----- SM Control Data ---------------- */ | ||
170 | u8 SM_DeviceID; | ||
171 | u8 SM_CardID; | ||
172 | |||
173 | unsigned char *testbuf; | ||
174 | u8 BIN_FLAG; | ||
175 | u32 bl_num; | ||
176 | int SrbStatus; | ||
177 | |||
178 | /*------Power Managerment ---------------*/ | ||
179 | bool Power_IsResum; | ||
180 | }; | ||
181 | |||
182 | static int ene_sd_init(struct us_data *us); | ||
183 | static int ene_load_bincode(struct us_data *us, unsigned char flag); | ||
184 | |||
185 | static void ene_ub6250_info_destructor(void *extra) | ||
186 | { | ||
187 | if (!extra) | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) | ||
192 | { | ||
193 | struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; | ||
194 | struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; | ||
195 | |||
196 | int result; | ||
197 | unsigned int residue; | ||
198 | unsigned int cswlen = 0, partial = 0; | ||
199 | unsigned int transfer_length = bcb->DataTransferLength; | ||
200 | |||
201 | /* US_DEBUGP("transport --- ene_send_scsi_cmd\n"); */ | ||
202 | /* send cmd to out endpoint */ | ||
203 | result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, | ||
204 | bcb, US_BULK_CB_WRAP_LEN, NULL); | ||
205 | if (result != USB_STOR_XFER_GOOD) { | ||
206 | US_DEBUGP("send cmd to out endpoint fail ---\n"); | ||
207 | return USB_STOR_TRANSPORT_ERROR; | ||
208 | } | ||
209 | |||
210 | if (buf) { | ||
211 | unsigned int pipe = fDir; | ||
212 | |||
213 | if (fDir == FDIR_READ) | ||
214 | pipe = us->recv_bulk_pipe; | ||
215 | else | ||
216 | pipe = us->send_bulk_pipe; | ||
217 | |||
218 | /* Bulk */ | ||
219 | if (use_sg) { | ||
220 | result = usb_stor_bulk_srb(us, pipe, us->srb); | ||
221 | } else { | ||
222 | result = usb_stor_bulk_transfer_sg(us, pipe, buf, | ||
223 | transfer_length, 0, &partial); | ||
224 | } | ||
225 | if (result != USB_STOR_XFER_GOOD) { | ||
226 | US_DEBUGP("data transfer fail ---\n"); | ||
227 | return USB_STOR_TRANSPORT_ERROR; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* Get CSW for device status */ | ||
232 | result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, | ||
233 | US_BULK_CS_WRAP_LEN, &cswlen); | ||
234 | |||
235 | if (result == USB_STOR_XFER_SHORT && cswlen == 0) { | ||
236 | US_DEBUGP("Received 0-length CSW; retrying...\n"); | ||
237 | result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, | ||
238 | bcs, US_BULK_CS_WRAP_LEN, &cswlen); | ||
239 | } | ||
240 | |||
241 | if (result == USB_STOR_XFER_STALLED) { | ||
242 | /* get the status again */ | ||
243 | US_DEBUGP("Attempting to get CSW (2nd try)...\n"); | ||
244 | result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, | ||
245 | bcs, US_BULK_CS_WRAP_LEN, NULL); | ||
246 | } | ||
247 | |||
248 | if (result != USB_STOR_XFER_GOOD) | ||
249 | return USB_STOR_TRANSPORT_ERROR; | ||
250 | |||
251 | /* check bulk status */ | ||
252 | residue = le32_to_cpu(bcs->Residue); | ||
253 | |||
254 | /* try to compute the actual residue, based on how much data | ||
255 | * was really transferred and what the device tells us */ | ||
256 | if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { | ||
257 | residue = min(residue, transfer_length); | ||
258 | if (us->srb != NULL) | ||
259 | scsi_set_resid(us->srb, max(scsi_get_resid(us->srb), | ||
260 | (int)residue)); | ||
261 | } | ||
262 | |||
263 | if (bcs->Status != US_BULK_STAT_OK) | ||
264 | return USB_STOR_TRANSPORT_ERROR; | ||
265 | |||
266 | return USB_STOR_TRANSPORT_GOOD; | ||
267 | } | ||
268 | |||
269 | static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) | ||
270 | { | ||
271 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
272 | |||
273 | if (info->SD_Status.Insert && info->SD_Status.Ready) | ||
274 | return USB_STOR_TRANSPORT_GOOD; | ||
275 | else { | ||
276 | ene_sd_init(us); | ||
277 | return USB_STOR_TRANSPORT_GOOD; | ||
278 | } | ||
279 | |||
280 | return USB_STOR_TRANSPORT_GOOD; | ||
281 | } | ||
282 | |||
283 | static int sd_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb) | ||
284 | { | ||
285 | unsigned char data_ptr[36] = { | ||
286 | 0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55, | ||
287 | 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61, | ||
288 | 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, | ||
289 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 }; | ||
290 | |||
291 | usb_stor_set_xfer_buf(data_ptr, 36, srb); | ||
292 | return USB_STOR_TRANSPORT_GOOD; | ||
293 | } | ||
294 | |||
295 | static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) | ||
296 | { | ||
297 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
298 | unsigned char mediaNoWP[12] = { | ||
299 | 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00, | ||
300 | 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; | ||
301 | unsigned char mediaWP[12] = { | ||
302 | 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, | ||
303 | 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; | ||
304 | |||
305 | if (info->SD_Status.WtP) | ||
306 | usb_stor_set_xfer_buf(mediaWP, 12, srb); | ||
307 | else | ||
308 | usb_stor_set_xfer_buf(mediaNoWP, 12, srb); | ||
309 | |||
310 | |||
311 | return USB_STOR_TRANSPORT_GOOD; | ||
312 | } | ||
313 | |||
314 | static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) | ||
315 | { | ||
316 | u32 bl_num; | ||
317 | u16 bl_len; | ||
318 | unsigned int offset = 0; | ||
319 | unsigned char buf[8]; | ||
320 | struct scatterlist *sg = NULL; | ||
321 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
322 | |||
323 | US_DEBUGP("sd_scsi_read_capacity\n"); | ||
324 | if (info->SD_Status.HiCapacity) { | ||
325 | bl_len = 0x200; | ||
326 | if (info->SD_Status.IsMMC) | ||
327 | bl_num = info->HC_C_SIZE-1; | ||
328 | else | ||
329 | bl_num = (info->HC_C_SIZE + 1) * 1024 - 1; | ||
330 | } else { | ||
331 | bl_len = 1<<(info->SD_READ_BL_LEN); | ||
332 | bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1) | ||
333 | * (1 << (info->SD_C_SIZE_MULT + 2)) - 1; | ||
334 | } | ||
335 | info->bl_num = bl_num; | ||
336 | US_DEBUGP("bl_len = %x\n", bl_len); | ||
337 | US_DEBUGP("bl_num = %x\n", bl_num); | ||
338 | |||
339 | /*srb->request_bufflen = 8; */ | ||
340 | buf[0] = (bl_num >> 24) & 0xff; | ||
341 | buf[1] = (bl_num >> 16) & 0xff; | ||
342 | buf[2] = (bl_num >> 8) & 0xff; | ||
343 | buf[3] = (bl_num >> 0) & 0xff; | ||
344 | buf[4] = (bl_len >> 24) & 0xff; | ||
345 | buf[5] = (bl_len >> 16) & 0xff; | ||
346 | buf[6] = (bl_len >> 8) & 0xff; | ||
347 | buf[7] = (bl_len >> 0) & 0xff; | ||
348 | |||
349 | usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF); | ||
350 | |||
351 | return USB_STOR_TRANSPORT_GOOD; | ||
352 | } | ||
353 | |||
354 | static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb) | ||
355 | { | ||
356 | int result; | ||
357 | unsigned char *cdb = srb->cmnd; | ||
358 | struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; | ||
359 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
360 | |||
361 | u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | | ||
362 | ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); | ||
363 | u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); | ||
364 | u32 bnByte = bn * 0x200; | ||
365 | u32 blenByte = blen * 0x200; | ||
366 | |||
367 | if (bn > info->bl_num) | ||
368 | return USB_STOR_TRANSPORT_ERROR; | ||
369 | |||
370 | result = ene_load_bincode(us, SD_RW_PATTERN); | ||
371 | if (result != USB_STOR_XFER_GOOD) { | ||
372 | US_DEBUGP("Load SD RW pattern Fail !!\n"); | ||
373 | return USB_STOR_TRANSPORT_ERROR; | ||
374 | } | ||
375 | |||
376 | if (info->SD_Status.HiCapacity) | ||
377 | bnByte = bn; | ||
378 | |||
379 | /* set up the command wrapper */ | ||
380 | memset(bcb, 0, sizeof(struct bulk_cb_wrap)); | ||
381 | bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); | ||
382 | bcb->DataTransferLength = blenByte; | ||
383 | bcb->Flags = 0x80; | ||
384 | bcb->CDB[0] = 0xF1; | ||
385 | bcb->CDB[5] = (unsigned char)(bnByte); | ||
386 | bcb->CDB[4] = (unsigned char)(bnByte>>8); | ||
387 | bcb->CDB[3] = (unsigned char)(bnByte>>16); | ||
388 | bcb->CDB[2] = (unsigned char)(bnByte>>24); | ||
389 | |||
390 | result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1); | ||
391 | return result; | ||
392 | } | ||
393 | |||
394 | static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb) | ||
395 | { | ||
396 | int result; | ||
397 | unsigned char *cdb = srb->cmnd; | ||
398 | struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; | ||
399 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
400 | |||
401 | u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | | ||
402 | ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); | ||
403 | u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); | ||
404 | u32 bnByte = bn * 0x200; | ||
405 | u32 blenByte = blen * 0x200; | ||
406 | |||
407 | if (bn > info->bl_num) | ||
408 | return USB_STOR_TRANSPORT_ERROR; | ||
409 | |||
410 | result = ene_load_bincode(us, SD_RW_PATTERN); | ||
411 | if (result != USB_STOR_XFER_GOOD) { | ||
412 | US_DEBUGP("Load SD RW pattern Fail !!\n"); | ||
413 | return USB_STOR_TRANSPORT_ERROR; | ||
414 | } | ||
415 | |||
416 | if (info->SD_Status.HiCapacity) | ||
417 | bnByte = bn; | ||
418 | |||
419 | /* set up the command wrapper */ | ||
420 | memset(bcb, 0, sizeof(struct bulk_cb_wrap)); | ||
421 | bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); | ||
422 | bcb->DataTransferLength = blenByte; | ||
423 | bcb->Flags = 0x00; | ||
424 | bcb->CDB[0] = 0xF0; | ||
425 | bcb->CDB[5] = (unsigned char)(bnByte); | ||
426 | bcb->CDB[4] = (unsigned char)(bnByte>>8); | ||
427 | bcb->CDB[3] = (unsigned char)(bnByte>>16); | ||
428 | bcb->CDB[2] = (unsigned char)(bnByte>>24); | ||
429 | |||
430 | result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1); | ||
431 | return result; | ||
432 | } | ||
433 | |||
434 | static int ene_get_card_type(struct us_data *us, u16 index, void *buf) | ||
435 | { | ||
436 | struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; | ||
437 | int result; | ||
438 | |||
439 | memset(bcb, 0, sizeof(struct bulk_cb_wrap)); | ||
440 | bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); | ||
441 | bcb->DataTransferLength = 0x01; | ||
442 | bcb->Flags = 0x80; | ||
443 | bcb->CDB[0] = 0xED; | ||
444 | bcb->CDB[2] = (unsigned char)(index>>8); | ||
445 | bcb->CDB[3] = (unsigned char)index; | ||
446 | |||
447 | result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0); | ||
448 | return result; | ||
449 | } | ||
450 | |||
451 | static int ene_get_card_status(struct us_data *us, u8 *buf) | ||
452 | { | ||
453 | u16 tmpreg; | ||
454 | u32 reg4b; | ||
455 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
456 | |||
457 | /*US_DEBUGP("transport --- ENE_ReadSDReg\n");*/ | ||
458 | reg4b = *(u32 *)&buf[0x18]; | ||
459 | info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f); | ||
460 | |||
461 | tmpreg = (u16) reg4b; | ||
462 | reg4b = *(u32 *)(&buf[0x14]); | ||
463 | if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC) | ||
464 | info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff; | ||
465 | |||
466 | info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22); | ||
467 | info->SD_C_SIZE_MULT = (u8)(reg4b >> 7) & 0x07; | ||
468 | if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC) | ||
469 | info->HC_C_SIZE = *(u32 *)(&buf[0x100]); | ||
470 | |||
471 | if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) { | ||
472 | info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN); | ||
473 | info->SD_READ_BL_LEN = SD_BLOCK_LEN; | ||
474 | } else { | ||
475 | info->SD_Block_Mult = 1; | ||
476 | } | ||
477 | |||
478 | return USB_STOR_TRANSPORT_GOOD; | ||
479 | } | ||
480 | |||
481 | static int ene_load_bincode(struct us_data *us, unsigned char flag) | ||
482 | { | ||
483 | int err; | ||
484 | char *fw_name = NULL; | ||
485 | unsigned char *buf = NULL; | ||
486 | const struct firmware *sd_fw = NULL; | ||
487 | int result = USB_STOR_TRANSPORT_ERROR; | ||
488 | struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; | ||
489 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
490 | |||
491 | if (info->BIN_FLAG == flag) | ||
492 | return USB_STOR_TRANSPORT_GOOD; | ||
493 | |||
494 | buf = kmalloc(ENE_BIN_CODE_LEN, GFP_KERNEL); | ||
495 | if (buf == NULL) | ||
496 | return USB_STOR_TRANSPORT_ERROR; | ||
497 | |||
498 | switch (flag) { | ||
499 | /* For SD */ | ||
500 | case SD_INIT1_PATTERN: | ||
501 | US_DEBUGP("SD_INIT1_PATTERN\n"); | ||
502 | fw_name = "ene-ub6250/sd_init1.bin"; | ||
503 | break; | ||
504 | case SD_INIT2_PATTERN: | ||
505 | US_DEBUGP("SD_INIT2_PATTERN\n"); | ||
506 | fw_name = "ene-ub6250/sd_init2.bin"; | ||
507 | break; | ||
508 | case SD_RW_PATTERN: | ||
509 | US_DEBUGP("SD_RDWR_PATTERN\n"); | ||
510 | fw_name = "ene-ub6250/sd_rdwr.bin"; | ||
511 | break; | ||
512 | default: | ||
513 | US_DEBUGP("----------- Unknown PATTERN ----------\n"); | ||
514 | goto nofw; | ||
515 | } | ||
516 | |||
517 | err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev); | ||
518 | if (err) { | ||
519 | US_DEBUGP("load firmware %s failed\n", fw_name); | ||
520 | goto nofw; | ||
521 | } | ||
522 | buf = kmalloc(sd_fw->size, GFP_KERNEL); | ||
523 | if (buf == NULL) { | ||
524 | US_DEBUGP("Malloc memory for fireware failed!\n"); | ||
525 | goto nofw; | ||
526 | } | ||
527 | memcpy(buf, sd_fw->data, sd_fw->size); | ||
528 | memset(bcb, 0, sizeof(struct bulk_cb_wrap)); | ||
529 | bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); | ||
530 | bcb->DataTransferLength = sd_fw->size; | ||
531 | bcb->Flags = 0x00; | ||
532 | bcb->CDB[0] = 0xEF; | ||
533 | |||
534 | result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0); | ||
535 | info->BIN_FLAG = flag; | ||
536 | kfree(buf); | ||
537 | |||
538 | nofw: | ||
539 | if (sd_fw != NULL) { | ||
540 | release_firmware(sd_fw); | ||
541 | sd_fw = NULL; | ||
542 | } | ||
543 | |||
544 | return result; | ||
545 | } | ||
546 | |||
547 | static int ene_sd_init(struct us_data *us) | ||
548 | { | ||
549 | int result; | ||
550 | u8 buf[0x200]; | ||
551 | struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; | ||
552 | struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; | ||
553 | |||
554 | US_DEBUGP("transport --- ENE_SDInit\n"); | ||
555 | /* SD Init Part-1 */ | ||
556 | result = ene_load_bincode(us, SD_INIT1_PATTERN); | ||
557 | if (result != USB_STOR_XFER_GOOD) { | ||
558 | US_DEBUGP("Load SD Init Code Part-1 Fail !!\n"); | ||
559 | return USB_STOR_TRANSPORT_ERROR; | ||
560 | } | ||
561 | |||
562 | memset(bcb, 0, sizeof(struct bulk_cb_wrap)); | ||
563 | bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); | ||
564 | bcb->Flags = 0x80; | ||
565 | bcb->CDB[0] = 0xF2; | ||
566 | |||
567 | result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); | ||
568 | if (result != USB_STOR_XFER_GOOD) { | ||
569 | US_DEBUGP("Exection SD Init Code Fail !!\n"); | ||
570 | return USB_STOR_TRANSPORT_ERROR; | ||
571 | } | ||
572 | |||
573 | /* SD Init Part-2 */ | ||
574 | result = ene_load_bincode(us, SD_INIT2_PATTERN); | ||
575 | if (result != USB_STOR_XFER_GOOD) { | ||
576 | US_DEBUGP("Load SD Init Code Part-2 Fail !!\n"); | ||
577 | return USB_STOR_TRANSPORT_ERROR; | ||
578 | } | ||
579 | |||
580 | memset(bcb, 0, sizeof(struct bulk_cb_wrap)); | ||
581 | bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); | ||
582 | bcb->DataTransferLength = 0x200; | ||
583 | bcb->Flags = 0x80; | ||
584 | bcb->CDB[0] = 0xF1; | ||
585 | |||
586 | result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0); | ||
587 | if (result != USB_STOR_XFER_GOOD) { | ||
588 | US_DEBUGP("Exection SD Init Code Fail !!\n"); | ||
589 | return USB_STOR_TRANSPORT_ERROR; | ||
590 | } | ||
591 | |||
592 | info->SD_Status = *(struct SD_STATUS *)&buf[0]; | ||
593 | if (info->SD_Status.Insert && info->SD_Status.Ready) { | ||
594 | ene_get_card_status(us, (unsigned char *)&buf); | ||
595 | US_DEBUGP("Insert = %x\n", info->SD_Status.Insert); | ||
596 | US_DEBUGP("Ready = %x\n", info->SD_Status.Ready); | ||
597 | US_DEBUGP("IsMMC = %x\n", info->SD_Status.IsMMC); | ||
598 | US_DEBUGP("HiCapacity = %x\n", info->SD_Status.HiCapacity); | ||
599 | US_DEBUGP("HiSpeed = %x\n", info->SD_Status.HiSpeed); | ||
600 | US_DEBUGP("WtP = %x\n", info->SD_Status.WtP); | ||
601 | } else { | ||
602 | US_DEBUGP("SD Card Not Ready --- %x\n", buf[0]); | ||
603 | return USB_STOR_TRANSPORT_ERROR; | ||
604 | } | ||
605 | return USB_STOR_TRANSPORT_GOOD; | ||
606 | } | ||
607 | |||
608 | |||
609 | static int ene_init(struct us_data *us) | ||
610 | { | ||
611 | int result; | ||
612 | u8 misc_reg03 = 0; | ||
613 | struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); | ||
614 | |||
615 | result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03); | ||
616 | if (result != USB_STOR_XFER_GOOD) | ||
617 | return USB_STOR_TRANSPORT_ERROR; | ||
618 | |||
619 | if (misc_reg03 & 0x01) { | ||
620 | if (!info->SD_Status.Ready) { | ||
621 | result = ene_sd_init(us); | ||
622 | if (result != USB_STOR_XFER_GOOD) | ||
623 | return USB_STOR_TRANSPORT_ERROR; | ||
624 | } | ||
625 | } | ||
626 | |||
627 | return result; | ||
628 | } | ||
629 | |||
630 | /*----- sd_scsi_irp() ---------*/ | ||
631 | static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) | ||
632 | { | ||
633 | int result; | ||
634 | struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra; | ||
635 | |||
636 | info->SrbStatus = SS_SUCCESS; | ||
637 | switch (srb->cmnd[0]) { | ||
638 | case TEST_UNIT_READY: | ||
639 | result = sd_scsi_test_unit_ready(us, srb); | ||
640 | break; /* 0x00 */ | ||
641 | case INQUIRY: | ||
642 | result = sd_scsi_inquiry(us, srb); | ||
643 | break; /* 0x12 */ | ||
644 | case MODE_SENSE: | ||
645 | result = sd_scsi_mode_sense(us, srb); | ||
646 | break; /* 0x1A */ | ||
647 | /* | ||
648 | case START_STOP: | ||
649 | result = SD_SCSI_Start_Stop(us, srb); | ||
650 | break; //0x1B | ||
651 | */ | ||
652 | case READ_CAPACITY: | ||
653 | result = sd_scsi_read_capacity(us, srb); | ||
654 | break; /* 0x25 */ | ||
655 | case READ_10: | ||
656 | result = sd_scsi_read(us, srb); | ||
657 | break; /* 0x28 */ | ||
658 | case WRITE_10: | ||
659 | result = sd_scsi_write(us, srb); | ||
660 | break; /* 0x2A */ | ||
661 | default: | ||
662 | info->SrbStatus = SS_ILLEGAL_REQUEST; | ||
663 | result = USB_STOR_TRANSPORT_FAILED; | ||
664 | break; | ||
665 | } | ||
666 | return result; | ||
667 | } | ||
668 | |||
669 | static int ene_transport(struct scsi_cmnd *srb, struct us_data *us) | ||
670 | { | ||
671 | int result = 0; | ||
672 | struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); | ||
673 | |||
674 | /*US_DEBUG(usb_stor_show_command(srb)); */ | ||
675 | scsi_set_resid(srb, 0); | ||
676 | if (unlikely(!info->SD_Status.Ready)) | ||
677 | result = ene_init(us); | ||
678 | else | ||
679 | result = sd_scsi_irp(us, srb); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | |||
685 | static int ene_ub6250_probe(struct usb_interface *intf, | ||
686 | const struct usb_device_id *id) | ||
687 | { | ||
688 | int result; | ||
689 | u8 misc_reg03 = 0; | ||
690 | struct us_data *us; | ||
691 | |||
692 | result = usb_stor_probe1(&us, intf, id, | ||
693 | (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list); | ||
694 | if (result) | ||
695 | return result; | ||
696 | |||
697 | /* FIXME: where should the code alloc extra buf ? */ | ||
698 | if (!us->extra) { | ||
699 | us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL); | ||
700 | if (!us->extra) | ||
701 | return -ENOMEM; | ||
702 | us->extra_destructor = ene_ub6250_info_destructor; | ||
703 | } | ||
704 | |||
705 | us->transport_name = "ene_ub6250"; | ||
706 | us->transport = ene_transport; | ||
707 | us->max_lun = 0; | ||
708 | |||
709 | result = usb_stor_probe2(us); | ||
710 | if (result) | ||
711 | return result; | ||
712 | |||
713 | /* probe card type */ | ||
714 | result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03); | ||
715 | if (result != USB_STOR_XFER_GOOD) { | ||
716 | usb_stor_disconnect(intf); | ||
717 | return USB_STOR_TRANSPORT_ERROR; | ||
718 | } | ||
719 | |||
720 | if (!(misc_reg03 & 0x01)) { | ||
721 | result = -ENODEV; | ||
722 | printk(KERN_NOTICE "ums_eneub6250: The driver only supports SD\ | ||
723 | card. To use SM/MS card, please build driver/stagging/keucr\n"); | ||
724 | usb_stor_disconnect(intf); | ||
725 | } | ||
726 | |||
727 | return result; | ||
728 | } | ||
729 | |||
730 | |||
731 | #ifdef CONFIG_PM | ||
732 | |||
733 | static int ene_ub6250_resume(struct usb_interface *iface) | ||
734 | { | ||
735 | u8 tmp = 0; | ||
736 | struct us_data *us = usb_get_intfdata(iface); | ||
737 | struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); | ||
738 | |||
739 | mutex_lock(&us->dev_mutex); | ||
740 | |||
741 | US_DEBUGP("%s\n", __func__); | ||
742 | if (us->suspend_resume_hook) | ||
743 | (us->suspend_resume_hook)(us, US_RESUME); | ||
744 | |||
745 | mutex_unlock(&us->dev_mutex); | ||
746 | |||
747 | info->Power_IsResum = true; | ||
748 | /*info->SD_Status.Ready = 0; */ | ||
749 | info->SD_Status = *(struct SD_STATUS *)&tmp; | ||
750 | info->MS_Status = *(struct MS_STATUS *)&tmp; | ||
751 | info->SM_Status = *(struct SM_STATUS *)&tmp; | ||
752 | |||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static int ene_ub6250_reset_resume(struct usb_interface *iface) | ||
757 | { | ||
758 | u8 tmp = 0; | ||
759 | struct us_data *us = usb_get_intfdata(iface); | ||
760 | struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); | ||
761 | US_DEBUGP("%s\n", __func__); | ||
762 | /* Report the reset to the SCSI core */ | ||
763 | usb_stor_reset_resume(iface); | ||
764 | |||
765 | /* FIXME: Notify the subdrivers that they need to reinitialize | ||
766 | * the device */ | ||
767 | info->Power_IsResum = true; | ||
768 | /*info->SD_Status.Ready = 0; */ | ||
769 | info->SD_Status = *(struct SD_STATUS *)&tmp; | ||
770 | info->MS_Status = *(struct MS_STATUS *)&tmp; | ||
771 | info->SM_Status = *(struct SM_STATUS *)&tmp; | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | #else | ||
777 | |||
778 | #define ene_ub6250_resume NULL | ||
779 | #define ene_ub6250_reset_resume NULL | ||
780 | |||
781 | #endif | ||
782 | |||
783 | static struct usb_driver ene_ub6250_driver = { | ||
784 | .name = "ums_eneub6250", | ||
785 | .probe = ene_ub6250_probe, | ||
786 | .disconnect = usb_stor_disconnect, | ||
787 | .suspend = usb_stor_suspend, | ||
788 | .resume = ene_ub6250_resume, | ||
789 | .reset_resume = ene_ub6250_reset_resume, | ||
790 | .pre_reset = usb_stor_pre_reset, | ||
791 | .post_reset = usb_stor_post_reset, | ||
792 | .id_table = ene_ub6250_usb_ids, | ||
793 | .soft_unbind = 1, | ||
794 | }; | ||
795 | |||
796 | static int __init ene_ub6250_init(void) | ||
797 | { | ||
798 | return usb_register(&ene_ub6250_driver); | ||
799 | } | ||
800 | |||
801 | static void __exit ene_ub6250_exit(void) | ||
802 | { | ||
803 | usb_deregister(&ene_ub6250_driver); | ||
804 | } | ||
805 | |||
806 | module_init(ene_ub6250_init); | ||
807 | module_exit(ene_ub6250_exit); | ||
diff --git a/drivers/usb/storage/unusual_ene_ub6250.h b/drivers/usb/storage/unusual_ene_ub6250.h new file mode 100644 index 00000000000..5667f5d365c --- /dev/null +++ b/drivers/usb/storage/unusual_ene_ub6250.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify it | ||
4 | * under the terms of the GNU General Public License as published by the | ||
5 | * Free Software Foundation; either version 2, or (at your option) any | ||
6 | * later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
16 | */ | ||
17 | |||
18 | #if defined(CONFIG_USB_STORAGE_ENE_UB6250) || \ | ||
19 | defined(CONFIG_USB_STORAGE_ENE_UB6250_MODULE) | ||
20 | |||
21 | UNUSUAL_DEV(0x0cf2, 0x6250, 0x0000, 0x9999, | ||
22 | "ENE", | ||
23 | "ENE UB6250 reader", | ||
24 | USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0), | ||
25 | |||
26 | #endif /* defined(CONFIG_USB_STORAGE_ENE_UB6250) || ... */ | ||
diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c index 468bde7d197..f0f60b6a2cf 100644 --- a/drivers/usb/storage/usual-tables.c +++ b/drivers/usb/storage/usual-tables.c | |||
@@ -80,6 +80,7 @@ static struct ignore_entry ignore_ids[] = { | |||
80 | # include "unusual_alauda.h" | 80 | # include "unusual_alauda.h" |
81 | # include "unusual_cypress.h" | 81 | # include "unusual_cypress.h" |
82 | # include "unusual_datafab.h" | 82 | # include "unusual_datafab.h" |
83 | # include "unusual_ene_ub6250.h" | ||
83 | # include "unusual_freecom.h" | 84 | # include "unusual_freecom.h" |
84 | # include "unusual_isd200.h" | 85 | # include "unusual_isd200.h" |
85 | # include "unusual_jumpshot.h" | 86 | # include "unusual_jumpshot.h" |