-
Notifications
You must be signed in to change notification settings - Fork 1
/
rts51x_common.c
192 lines (151 loc) · 5.44 KB
/
rts51x_common.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* Driver for Realtek RTS51xx USB card reader
*
* Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http:
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include "timestamp.h"
#include "rts51x.h"
#include "rts51x_chip.h"
/***********************************************************************
* Host functions
***********************************************************************/
const char* host_info(struct Scsi_Host *host)
{
return "SCSI emulation for RTS51xx USB driver-based card reader";
}
int slave_alloc (struct scsi_device *sdev)
{
/*
* Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or
* less than 36 bytes.
*/
sdev->inquiry_len = 36;
return 0;
}
int slave_configure(struct scsi_device *sdev)
{
/* Scatter-gather buffers (all but the last) must have a length
* divisible by the bulk maxpacket size. Otherwise a data packet
* would end up being short, causing a premature end to the data
* transfer. Since high-speed bulk pipes have a maxpacket size
* of 512, we'll use that as the scsi device queue's DMA alignment
* mask. Guaranteeing proper alignment of the first buffer will
* have the desired effect because, except at the beginning and
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
/* Set the SCSI level to at least 2. We'll leave it at 3 if that's
* what is originally reported. We need this to avoid confusing
* the SCSI layer with devices that report 0 or 1, but need 10-byte
* commands (ala ATAPI devices behind certain bridges, or devices
* which simply have broken INQUIRY data).
*
* NOTE: This means /dev/sg programs (ala cdrecord) will get the
* actual information. This seems to be the preference for
* programs like that.
*
* NOTE: This also means that /proc/scsi/scsi and sysfs may report
* the actual value or the modified one, depending on where the
* data comes from.
*/
if (sdev->scsi_level < SCSI_2)
sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
return 0;
}
/***********************************************************************
* /proc/scsi/ functions
***********************************************************************/
#undef SPRINTF
#define SPRINTF(args...) \
do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
int queuecommand_lck(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct rts51x_chip *chip = host_to_rts51x(srb->device->host);
if (chip->srb != NULL) {
RTS51X_DEBUGP(("Error in %s: chip->srb = %p\n",
__FUNCTION__, chip->srb));
return SCSI_MLQUEUE_HOST_BUSY;
}
if (test_bit(FLIDX_DISCONNECTING, &chip->usb->dflags)) {
RTS51X_DEBUGP(("Fail command during disconnect\n"));
srb->result = DID_NO_CONNECT << 16;
done(srb);
return 0;
}
srb->scsi_done = done;
chip->srb = srb;
complete(&chip->usb->cmnd_ready);
return 0;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
int queuecommand(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
return queuecommand_lck(srb, done);
}
#else
DEF_SCSI_QCMD(queuecommand)
#endif
/***********************************************************************
* Error handling functions
***********************************************************************/
int command_abort(struct scsi_cmnd *srb)
{
struct rts51x_chip *chip = host_to_rts51x(srb->device->host);
RTS51X_DEBUGP(("%s called\n", __func__));
/* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
* bits are protected by the host lock. */
scsi_lock(rts51x_to_host(chip));
if (chip->srb != srb) {
scsi_unlock(rts51x_to_host(chip));
RTS51X_DEBUGP(("-- nothing to abort\n"));
return FAILED;
}
/* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
* a device reset isn't already in progress (to avoid interfering
* with the reset). Note that we must retain the host lock while
* calling usb_stor_stop_transport(); otherwise it might interfere
* with an auto-reset that begins as soon as we release the lock. */
set_bit(FLIDX_TIMED_OUT, &chip->usb->dflags);
if (!test_bit(FLIDX_RESETTING, &chip->usb->dflags)) {
set_bit(FLIDX_ABORTING, &chip->usb->dflags);
}
scsi_unlock(rts51x_to_host(chip));
wait_for_completion(&chip->usb->notify);
return SUCCESS;
}
/* This invokes the transport reset mechanism to reset the state of the
* device */
int device_reset(struct scsi_cmnd *srb)
{
int result = 0;
RTS51X_DEBUGP(("%s called\n", __FUNCTION__));
return result < 0 ? FAILED : SUCCESS;
}
int bus_reset(struct scsi_cmnd *srb)
{
int result = 0;
RTS51X_DEBUGP(("%s called\n", __FUNCTION__));
return result < 0 ? FAILED : SUCCESS;
}