diff options
Diffstat (limited to 'drivers/usb/storage/alauda.c')
-rw-r--r-- | drivers/usb/storage/alauda.c | 192 |
1 files changed, 180 insertions, 12 deletions
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 8d3711a7ff06..67edc65acb8e 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c | |||
@@ -31,6 +31,8 @@ | |||
31 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 31 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/module.h> | ||
35 | |||
34 | #include <scsi/scsi.h> | 36 | #include <scsi/scsi.h> |
35 | #include <scsi/scsi_cmnd.h> | 37 | #include <scsi/scsi_cmnd.h> |
36 | #include <scsi/scsi_device.h> | 38 | #include <scsi/scsi_device.h> |
@@ -39,7 +41,79 @@ | |||
39 | #include "transport.h" | 41 | #include "transport.h" |
40 | #include "protocol.h" | 42 | #include "protocol.h" |
41 | #include "debug.h" | 43 | #include "debug.h" |
42 | #include "alauda.h" | 44 | |
45 | MODULE_DESCRIPTION("Driver for Alauda-based card readers"); | ||
46 | MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | |||
49 | /* | ||
50 | * Status bytes | ||
51 | */ | ||
52 | #define ALAUDA_STATUS_ERROR 0x01 | ||
53 | #define ALAUDA_STATUS_READY 0x40 | ||
54 | |||
55 | /* | ||
56 | * Control opcodes (for request field) | ||
57 | */ | ||
58 | #define ALAUDA_GET_XD_MEDIA_STATUS 0x08 | ||
59 | #define ALAUDA_GET_SM_MEDIA_STATUS 0x98 | ||
60 | #define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a | ||
61 | #define ALAUDA_ACK_SM_MEDIA_CHANGE 0x9a | ||
62 | #define ALAUDA_GET_XD_MEDIA_SIG 0x86 | ||
63 | #define ALAUDA_GET_SM_MEDIA_SIG 0x96 | ||
64 | |||
65 | /* | ||
66 | * Bulk command identity (byte 0) | ||
67 | */ | ||
68 | #define ALAUDA_BULK_CMD 0x40 | ||
69 | |||
70 | /* | ||
71 | * Bulk opcodes (byte 1) | ||
72 | */ | ||
73 | #define ALAUDA_BULK_GET_REDU_DATA 0x85 | ||
74 | #define ALAUDA_BULK_READ_BLOCK 0x94 | ||
75 | #define ALAUDA_BULK_ERASE_BLOCK 0xa3 | ||
76 | #define ALAUDA_BULK_WRITE_BLOCK 0xb4 | ||
77 | #define ALAUDA_BULK_GET_STATUS2 0xb7 | ||
78 | #define ALAUDA_BULK_RESET_MEDIA 0xe0 | ||
79 | |||
80 | /* | ||
81 | * Port to operate on (byte 8) | ||
82 | */ | ||
83 | #define ALAUDA_PORT_XD 0x00 | ||
84 | #define ALAUDA_PORT_SM 0x01 | ||
85 | |||
86 | /* | ||
87 | * LBA and PBA are unsigned ints. Special values. | ||
88 | */ | ||
89 | #define UNDEF 0xffff | ||
90 | #define SPARE 0xfffe | ||
91 | #define UNUSABLE 0xfffd | ||
92 | |||
93 | struct alauda_media_info { | ||
94 | unsigned long capacity; /* total media size in bytes */ | ||
95 | unsigned int pagesize; /* page size in bytes */ | ||
96 | unsigned int blocksize; /* number of pages per block */ | ||
97 | unsigned int uzonesize; /* number of usable blocks per zone */ | ||
98 | unsigned int zonesize; /* number of blocks per zone */ | ||
99 | unsigned int blockmask; /* mask to get page from address */ | ||
100 | |||
101 | unsigned char pageshift; | ||
102 | unsigned char blockshift; | ||
103 | unsigned char zoneshift; | ||
104 | |||
105 | u16 **lba_to_pba; /* logical to physical block map */ | ||
106 | u16 **pba_to_lba; /* physical to logical block map */ | ||
107 | }; | ||
108 | |||
109 | struct alauda_info { | ||
110 | struct alauda_media_info port[2]; | ||
111 | int wr_ep; /* endpoint to write data out of */ | ||
112 | |||
113 | unsigned char sense_key; | ||
114 | unsigned long sense_asc; /* additional sense code */ | ||
115 | unsigned long sense_ascq; /* additional sense code qualifier */ | ||
116 | }; | ||
43 | 117 | ||
44 | #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) | 118 | #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) |
45 | #define LSB_of(s) ((s)&0xFF) | 119 | #define LSB_of(s) ((s)&0xFF) |
@@ -52,6 +126,48 @@ | |||
52 | #define PBA_HI(pba) (pba >> 3) | 126 | #define PBA_HI(pba) (pba >> 3) |
53 | #define PBA_ZONE(pba) (pba >> 11) | 127 | #define PBA_ZONE(pba) (pba >> 11) |
54 | 128 | ||
129 | static int init_alauda(struct us_data *us); | ||
130 | |||
131 | |||
132 | /* | ||
133 | * The table of devices | ||
134 | */ | ||
135 | #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ | ||
136 | vendorName, productName, useProtocol, useTransport, \ | ||
137 | initFunction, flags) \ | ||
138 | { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ | ||
139 | .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } | ||
140 | |||
141 | struct usb_device_id alauda_usb_ids[] = { | ||
142 | # include "unusual_alauda.h" | ||
143 | { } /* Terminating entry */ | ||
144 | }; | ||
145 | MODULE_DEVICE_TABLE(usb, alauda_usb_ids); | ||
146 | |||
147 | #undef UNUSUAL_DEV | ||
148 | |||
149 | /* | ||
150 | * The flags table | ||
151 | */ | ||
152 | #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ | ||
153 | vendor_name, product_name, use_protocol, use_transport, \ | ||
154 | init_function, Flags) \ | ||
155 | { \ | ||
156 | .vendorName = vendor_name, \ | ||
157 | .productName = product_name, \ | ||
158 | .useProtocol = use_protocol, \ | ||
159 | .useTransport = use_transport, \ | ||
160 | .initFunction = init_function, \ | ||
161 | } | ||
162 | |||
163 | static struct us_unusual_dev alauda_unusual_dev_list[] = { | ||
164 | # include "unusual_alauda.h" | ||
165 | { } /* Terminating entry */ | ||
166 | }; | ||
167 | |||
168 | #undef UNUSUAL_DEV | ||
169 | |||
170 | |||
55 | /* | 171 | /* |
56 | * Media handling | 172 | * Media handling |
57 | */ | 173 | */ |
@@ -307,7 +423,8 @@ static int alauda_init_media(struct us_data *us) | |||
307 | data[0], data[1], data[2], data[3]); | 423 | data[0], data[1], data[2], data[3]); |
308 | media_info = alauda_card_find_id(data[1]); | 424 | media_info = alauda_card_find_id(data[1]); |
309 | if (media_info == NULL) { | 425 | if (media_info == NULL) { |
310 | printk("alauda_init_media: Unrecognised media signature: " | 426 | printk(KERN_WARNING |
427 | "alauda_init_media: Unrecognised media signature: " | ||
311 | "%02X %02X %02X %02X\n", | 428 | "%02X %02X %02X %02X\n", |
312 | data[0], data[1], data[2], data[3]); | 429 | data[0], data[1], data[2], data[3]); |
313 | return USB_STOR_TRANSPORT_ERROR; | 430 | return USB_STOR_TRANSPORT_ERROR; |
@@ -518,7 +635,8 @@ static int alauda_read_map(struct us_data *us, unsigned int zone) | |||
518 | 635 | ||
519 | /* check even parity */ | 636 | /* check even parity */ |
520 | if (parity[data[6] ^ data[7]]) { | 637 | if (parity[data[6] ^ data[7]]) { |
521 | printk("alauda_read_map: Bad parity in LBA for block %d" | 638 | printk(KERN_WARNING |
639 | "alauda_read_map: Bad parity in LBA for block %d" | ||
522 | " (%02X %02X)\n", i, data[6], data[7]); | 640 | " (%02X %02X)\n", i, data[6], data[7]); |
523 | pba_to_lba[i] = UNUSABLE; | 641 | pba_to_lba[i] = UNUSABLE; |
524 | continue; | 642 | continue; |
@@ -538,13 +656,16 @@ static int alauda_read_map(struct us_data *us, unsigned int zone) | |||
538 | */ | 656 | */ |
539 | 657 | ||
540 | if (lba_offset >= uzonesize) { | 658 | if (lba_offset >= uzonesize) { |
541 | printk("alauda_read_map: Bad low LBA %d for block %d\n", | 659 | printk(KERN_WARNING |
660 | "alauda_read_map: Bad low LBA %d for block %d\n", | ||
542 | lba_real, blocknum); | 661 | lba_real, blocknum); |
543 | continue; | 662 | continue; |
544 | } | 663 | } |
545 | 664 | ||
546 | if (lba_to_pba[lba_offset] != UNDEF) { | 665 | if (lba_to_pba[lba_offset] != UNDEF) { |
547 | printk("alauda_read_map: LBA %d seen for PBA %d and %d\n", | 666 | printk(KERN_WARNING |
667 | "alauda_read_map: " | ||
668 | "LBA %d seen for PBA %d and %d\n", | ||
548 | lba_real, lba_to_pba[lba_offset], blocknum); | 669 | lba_real, lba_to_pba[lba_offset], blocknum); |
549 | continue; | 670 | continue; |
550 | } | 671 | } |
@@ -712,13 +833,15 @@ static int alauda_write_lba(struct us_data *us, u16 lba, | |||
712 | if (pba == 1) { | 833 | if (pba == 1) { |
713 | /* Maybe it is impossible to write to PBA 1. | 834 | /* Maybe it is impossible to write to PBA 1. |
714 | Fake success, but don't do anything. */ | 835 | Fake success, but don't do anything. */ |
715 | printk("alauda_write_lba: avoid writing to pba 1\n"); | 836 | printk(KERN_WARNING |
837 | "alauda_write_lba: avoid writing to pba 1\n"); | ||
716 | return USB_STOR_TRANSPORT_GOOD; | 838 | return USB_STOR_TRANSPORT_GOOD; |
717 | } | 839 | } |
718 | 840 | ||
719 | new_pba = alauda_find_unused_pba(&MEDIA_INFO(us), zone); | 841 | new_pba = alauda_find_unused_pba(&MEDIA_INFO(us), zone); |
720 | if (!new_pba) { | 842 | if (!new_pba) { |
721 | printk("alauda_write_lba: Out of unused blocks\n"); | 843 | printk(KERN_WARNING |
844 | "alauda_write_lba: Out of unused blocks\n"); | ||
722 | return USB_STOR_TRANSPORT_ERROR; | 845 | return USB_STOR_TRANSPORT_ERROR; |
723 | } | 846 | } |
724 | 847 | ||
@@ -818,7 +941,7 @@ static int alauda_read_data(struct us_data *us, unsigned long address, | |||
818 | len = min(sectors, blocksize) * (pagesize + 64); | 941 | len = min(sectors, blocksize) * (pagesize + 64); |
819 | buffer = kmalloc(len, GFP_NOIO); | 942 | buffer = kmalloc(len, GFP_NOIO); |
820 | if (buffer == NULL) { | 943 | if (buffer == NULL) { |
821 | printk("alauda_read_data: Out of memory\n"); | 944 | printk(KERN_WARNING "alauda_read_data: Out of memory\n"); |
822 | return USB_STOR_TRANSPORT_ERROR; | 945 | return USB_STOR_TRANSPORT_ERROR; |
823 | } | 946 | } |
824 | 947 | ||
@@ -911,7 +1034,7 @@ static int alauda_write_data(struct us_data *us, unsigned long address, | |||
911 | len = min(sectors, blocksize) * pagesize; | 1034 | len = min(sectors, blocksize) * pagesize; |
912 | buffer = kmalloc(len, GFP_NOIO); | 1035 | buffer = kmalloc(len, GFP_NOIO); |
913 | if (buffer == NULL) { | 1036 | if (buffer == NULL) { |
914 | printk("alauda_write_data: Out of memory\n"); | 1037 | printk(KERN_WARNING "alauda_write_data: Out of memory\n"); |
915 | return USB_STOR_TRANSPORT_ERROR; | 1038 | return USB_STOR_TRANSPORT_ERROR; |
916 | } | 1039 | } |
917 | 1040 | ||
@@ -921,7 +1044,7 @@ static int alauda_write_data(struct us_data *us, unsigned long address, | |||
921 | */ | 1044 | */ |
922 | blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO); | 1045 | blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO); |
923 | if (blockbuffer == NULL) { | 1046 | if (blockbuffer == NULL) { |
924 | printk("alauda_write_data: Out of memory\n"); | 1047 | printk(KERN_WARNING "alauda_write_data: Out of memory\n"); |
925 | kfree(buffer); | 1048 | kfree(buffer); |
926 | return USB_STOR_TRANSPORT_ERROR; | 1049 | return USB_STOR_TRANSPORT_ERROR; |
927 | } | 1050 | } |
@@ -991,7 +1114,7 @@ static void alauda_info_destructor(void *extra) | |||
991 | /* | 1114 | /* |
992 | * Initialize alauda_info struct and find the data-write endpoint | 1115 | * Initialize alauda_info struct and find the data-write endpoint |
993 | */ | 1116 | */ |
994 | int init_alauda(struct us_data *us) | 1117 | static int init_alauda(struct us_data *us) |
995 | { | 1118 | { |
996 | struct alauda_info *info; | 1119 | struct alauda_info *info; |
997 | struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting; | 1120 | struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting; |
@@ -1013,7 +1136,7 @@ int init_alauda(struct us_data *us) | |||
1013 | return USB_STOR_TRANSPORT_GOOD; | 1136 | return USB_STOR_TRANSPORT_GOOD; |
1014 | } | 1137 | } |
1015 | 1138 | ||
1016 | int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) | 1139 | static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) |
1017 | { | 1140 | { |
1018 | int rc; | 1141 | int rc; |
1019 | struct alauda_info *info = (struct alauda_info *) us->extra; | 1142 | struct alauda_info *info = (struct alauda_info *) us->extra; |
@@ -1121,3 +1244,48 @@ int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
1121 | return USB_STOR_TRANSPORT_FAILED; | 1244 | return USB_STOR_TRANSPORT_FAILED; |
1122 | } | 1245 | } |
1123 | 1246 | ||
1247 | static int alauda_probe(struct usb_interface *intf, | ||
1248 | const struct usb_device_id *id) | ||
1249 | { | ||
1250 | struct us_data *us; | ||
1251 | int result; | ||
1252 | |||
1253 | result = usb_stor_probe1(&us, intf, id, | ||
1254 | (id - alauda_usb_ids) + alauda_unusual_dev_list); | ||
1255 | if (result) | ||
1256 | return result; | ||
1257 | |||
1258 | us->transport_name = "Alauda Control/Bulk"; | ||
1259 | us->transport = alauda_transport; | ||
1260 | us->transport_reset = usb_stor_Bulk_reset; | ||
1261 | us->max_lun = 1; | ||
1262 | |||
1263 | result = usb_stor_probe2(us); | ||
1264 | return result; | ||
1265 | } | ||
1266 | |||
1267 | static struct usb_driver alauda_driver = { | ||
1268 | .name = "ums-alauda", | ||
1269 | .probe = alauda_probe, | ||
1270 | .disconnect = usb_stor_disconnect, | ||
1271 | .suspend = usb_stor_suspend, | ||
1272 | .resume = usb_stor_resume, | ||
1273 | .reset_resume = usb_stor_reset_resume, | ||
1274 | .pre_reset = usb_stor_pre_reset, | ||
1275 | .post_reset = usb_stor_post_reset, | ||
1276 | .id_table = alauda_usb_ids, | ||
1277 | .soft_unbind = 1, | ||
1278 | }; | ||
1279 | |||
1280 | static int __init alauda_init(void) | ||
1281 | { | ||
1282 | return usb_register(&alauda_driver); | ||
1283 | } | ||
1284 | |||
1285 | static void __exit alauda_exit(void) | ||
1286 | { | ||
1287 | usb_deregister(&alauda_driver); | ||
1288 | } | ||
1289 | |||
1290 | module_init(alauda_init); | ||
1291 | module_exit(alauda_exit); | ||