diff options
Diffstat (limited to 'drivers/block/paride')
29 files changed, 10552 insertions, 0 deletions
diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig new file mode 100644 index 000000000000..17ff40561257 --- /dev/null +++ b/drivers/block/paride/Kconfig | |||
@@ -0,0 +1,305 @@ | |||
1 | # | ||
2 | # PARIDE configuration | ||
3 | # | ||
4 | # PARIDE doesn't need PARPORT, but if PARPORT is configured as a module, | ||
5 | # PARIDE must also be a module. The bogus CONFIG_PARIDE_PARPORT option | ||
6 | # controls the choices given to the user ... | ||
7 | config PARIDE_PARPORT | ||
8 | tristate | ||
9 | depends on PARIDE!=n | ||
10 | default m if PARPORT=m | ||
11 | default y if PARPORT!=m | ||
12 | |||
13 | comment "Parallel IDE high-level drivers" | ||
14 | depends on PARIDE | ||
15 | |||
16 | config PARIDE_PD | ||
17 | tristate "Parallel port IDE disks" | ||
18 | depends on PARIDE | ||
19 | help | ||
20 | This option enables the high-level driver for IDE-type disk devices | ||
21 | connected through a parallel port. If you chose to build PARIDE | ||
22 | support into your kernel, you may answer Y here to build in the | ||
23 | parallel port IDE driver, otherwise you should answer M to build | ||
24 | it as a loadable module. The module will be called pd. You | ||
25 | must also have at least one parallel port protocol driver in your | ||
26 | system. Among the devices supported by this driver are the SyQuest | ||
27 | EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack | ||
28 | hard drives from MicroSolutions. | ||
29 | |||
30 | config PARIDE_PCD | ||
31 | tristate "Parallel port ATAPI CD-ROMs" | ||
32 | depends on PARIDE | ||
33 | ---help--- | ||
34 | This option enables the high-level driver for ATAPI CD-ROM devices | ||
35 | connected through a parallel port. If you chose to build PARIDE | ||
36 | support into your kernel, you may answer Y here to build in the | ||
37 | parallel port ATAPI CD-ROM driver, otherwise you should answer M to | ||
38 | build it as a loadable module. The module will be called pcd. You | ||
39 | must also have at least one parallel port protocol driver in your | ||
40 | system. Among the devices supported by this driver are the | ||
41 | MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If | ||
42 | you have such a CD-ROM drive, you should also say Y or M to "ISO | ||
43 | 9660 CD-ROM file system support" below, because that's the file | ||
44 | system used on CD-ROMs. | ||
45 | |||
46 | config PARIDE_PF | ||
47 | tristate "Parallel port ATAPI disks" | ||
48 | depends on PARIDE | ||
49 | help | ||
50 | This option enables the high-level driver for ATAPI disk devices | ||
51 | connected through a parallel port. If you chose to build PARIDE | ||
52 | support into your kernel, you may answer Y here to build in the | ||
53 | parallel port ATAPI disk driver, otherwise you should answer M | ||
54 | to build it as a loadable module. The module will be called pf. | ||
55 | You must also have at least one parallel port protocol driver in | ||
56 | your system. Among the devices supported by this driver are the | ||
57 | MicroSolutions backpack PD/CD drive and the Imation Superdisk | ||
58 | LS-120 drive. | ||
59 | |||
60 | config PARIDE_PT | ||
61 | tristate "Parallel port ATAPI tapes" | ||
62 | depends on PARIDE | ||
63 | help | ||
64 | This option enables the high-level driver for ATAPI tape devices | ||
65 | connected through a parallel port. If you chose to build PARIDE | ||
66 | support into your kernel, you may answer Y here to build in the | ||
67 | parallel port ATAPI disk driver, otherwise you should answer M | ||
68 | to build it as a loadable module. The module will be called pt. | ||
69 | You must also have at least one parallel port protocol driver in | ||
70 | your system. Among the devices supported by this driver is the | ||
71 | parallel port version of the HP 5GB drive. | ||
72 | |||
73 | config PARIDE_PG | ||
74 | tristate "Parallel port generic ATAPI devices" | ||
75 | depends on PARIDE | ||
76 | ---help--- | ||
77 | This option enables a special high-level driver for generic ATAPI | ||
78 | devices connected through a parallel port. The driver allows user | ||
79 | programs, such as cdrtools, to send ATAPI commands directly to a | ||
80 | device. | ||
81 | |||
82 | If you chose to build PARIDE support into your kernel, you may | ||
83 | answer Y here to build in the parallel port generic ATAPI driver, | ||
84 | otherwise you should answer M to build it as a loadable module. The | ||
85 | module will be called pg. | ||
86 | |||
87 | You must also have at least one parallel port protocol driver in | ||
88 | your system. | ||
89 | |||
90 | This driver implements an API loosely related to the generic SCSI | ||
91 | driver. See <file:include/linux/pg.h>. for details. | ||
92 | |||
93 | You can obtain the most recent version of cdrtools from | ||
94 | <ftp://ftp.berlios.de/pub/cdrecord/>. Versions 1.6.1a3 and | ||
95 | later fully support this driver. | ||
96 | |||
97 | comment "Parallel IDE protocol modules" | ||
98 | depends on PARIDE | ||
99 | |||
100 | config PARIDE_ATEN | ||
101 | tristate "ATEN EH-100 protocol" | ||
102 | depends on PARIDE | ||
103 | help | ||
104 | This option enables support for the ATEN EH-100 parallel port IDE | ||
105 | protocol. This protocol is used in some inexpensive low performance | ||
106 | parallel port kits made in Hong Kong. If you chose to build PARIDE | ||
107 | support into your kernel, you may answer Y here to build in the | ||
108 | protocol driver, otherwise you should answer M to build it as a | ||
109 | loadable module. The module will be called aten. You must also | ||
110 | have a high-level driver for the type of device that you want to | ||
111 | support. | ||
112 | |||
113 | config PARIDE_BPCK | ||
114 | tristate "MicroSolutions backpack (Series 5) protocol" | ||
115 | depends on PARIDE | ||
116 | ---help--- | ||
117 | This option enables support for the Micro Solutions BACKPACK | ||
118 | parallel port Series 5 IDE protocol. (Most BACKPACK drives made | ||
119 | before 1999 were Series 5) Series 5 drives will NOT always have the | ||
120 | Series noted on the bottom of the drive. Series 6 drivers will. | ||
121 | |||
122 | In other words, if your BACKPACK drive doesn't say "Series 6" on the | ||
123 | bottom, enable this option. | ||
124 | |||
125 | If you chose to build PARIDE support into your kernel, you may | ||
126 | answer Y here to build in the protocol driver, otherwise you should | ||
127 | answer M to build it as a loadable module. The module will be | ||
128 | called bpck. You must also have a high-level driver for the type | ||
129 | of device that you want to support. | ||
130 | |||
131 | config PARIDE_BPCK6 | ||
132 | tristate "MicroSolutions backpack (Series 6) protocol" | ||
133 | depends on PARIDE && !64BIT | ||
134 | ---help--- | ||
135 | This option enables support for the Micro Solutions BACKPACK | ||
136 | parallel port Series 6 IDE protocol. (Most BACKPACK drives made | ||
137 | after 1999 were Series 6) Series 6 drives will have the Series noted | ||
138 | on the bottom of the drive. Series 5 drivers don't always have it | ||
139 | noted. | ||
140 | |||
141 | In other words, if your BACKPACK drive says "Series 6" on the | ||
142 | bottom, enable this option. | ||
143 | |||
144 | If you chose to build PARIDE support into your kernel, you may | ||
145 | answer Y here to build in the protocol driver, otherwise you should | ||
146 | answer M to build it as a loadable module. The module will be | ||
147 | called bpck6. You must also have a high-level driver for the type | ||
148 | of device that you want to support. | ||
149 | |||
150 | config PARIDE_COMM | ||
151 | tristate "DataStor Commuter protocol" | ||
152 | depends on PARIDE | ||
153 | help | ||
154 | This option enables support for the Commuter parallel port IDE | ||
155 | protocol from DataStor. If you chose to build PARIDE support | ||
156 | into your kernel, you may answer Y here to build in the protocol | ||
157 | driver, otherwise you should answer M to build it as a loadable | ||
158 | module. The module will be called comm. You must also have | ||
159 | a high-level driver for the type of device that you want to support. | ||
160 | |||
161 | config PARIDE_DSTR | ||
162 | tristate "DataStor EP-2000 protocol" | ||
163 | depends on PARIDE | ||
164 | help | ||
165 | This option enables support for the EP-2000 parallel port IDE | ||
166 | protocol from DataStor. If you chose to build PARIDE support | ||
167 | into your kernel, you may answer Y here to build in the protocol | ||
168 | driver, otherwise you should answer M to build it as a loadable | ||
169 | module. The module will be called dstr. You must also have | ||
170 | a high-level driver for the type of device that you want to support. | ||
171 | |||
172 | config PARIDE_FIT2 | ||
173 | tristate "FIT TD-2000 protocol" | ||
174 | depends on PARIDE | ||
175 | help | ||
176 | This option enables support for the TD-2000 parallel port IDE | ||
177 | protocol from Fidelity International Technology. This is a simple | ||
178 | (low speed) adapter that is used in some portable hard drives. If | ||
179 | you chose to build PARIDE support into your kernel, you may answer Y | ||
180 | here to build in the protocol driver, otherwise you should answer M | ||
181 | to build it as a loadable module. The module will be called ktti. | ||
182 | You must also have a high-level driver for the type of device that | ||
183 | you want to support. | ||
184 | |||
185 | config PARIDE_FIT3 | ||
186 | tristate "FIT TD-3000 protocol" | ||
187 | depends on PARIDE | ||
188 | help | ||
189 | This option enables support for the TD-3000 parallel port IDE | ||
190 | protocol from Fidelity International Technology. This protocol is | ||
191 | used in newer models of their portable disk, CD-ROM and PD/CD | ||
192 | devices. If you chose to build PARIDE support into your kernel, you | ||
193 | may answer Y here to build in the protocol driver, otherwise you | ||
194 | should answer M to build it as a loadable module. The module will be | ||
195 | called fit3. You must also have a high-level driver for the type | ||
196 | of device that you want to support. | ||
197 | |||
198 | config PARIDE_EPAT | ||
199 | tristate "Shuttle EPAT/EPEZ protocol" | ||
200 | depends on PARIDE | ||
201 | help | ||
202 | This option enables support for the EPAT parallel port IDE protocol. | ||
203 | EPAT is a parallel port IDE adapter manufactured by Shuttle | ||
204 | Technology and widely used in devices from major vendors such as | ||
205 | Hewlett-Packard, SyQuest, Imation and Avatar. If you chose to build | ||
206 | PARIDE support into your kernel, you may answer Y here to build in | ||
207 | the protocol driver, otherwise you should answer M to build it as a | ||
208 | loadable module. The module will be called epat. You must also | ||
209 | have a high-level driver for the type of device that you want to | ||
210 | support. | ||
211 | |||
212 | config PARIDE_EPATC8 | ||
213 | bool "Support c7/c8 chips (EXPERIMENTAL)" | ||
214 | depends on PARIDE_EPAT && EXPERIMENTAL | ||
215 | help | ||
216 | This option enables support for the newer Shuttle EP1284 (aka c7 and | ||
217 | c8) chip. You need this if you are using any recent Imation SuperDisk | ||
218 | (LS-120) drive. | ||
219 | |||
220 | config PARIDE_EPIA | ||
221 | tristate "Shuttle EPIA protocol" | ||
222 | depends on PARIDE | ||
223 | help | ||
224 | This option enables support for the (obsolete) EPIA parallel port | ||
225 | IDE protocol from Shuttle Technology. This adapter can still be | ||
226 | found in some no-name kits. If you chose to build PARIDE support | ||
227 | into your kernel, you may answer Y here to build in the protocol | ||
228 | driver, otherwise you should answer M to build it as a loadable | ||
229 | module. The module will be called epia. You must also have a | ||
230 | high-level driver for the type of device that you want to support. | ||
231 | |||
232 | config PARIDE_FRIQ | ||
233 | tristate "Freecom IQ ASIC-2 protocol" | ||
234 | depends on PARIDE | ||
235 | help | ||
236 | This option enables support for version 2 of the Freecom IQ parallel | ||
237 | port IDE adapter. This adapter is used by the Maxell Superdisk | ||
238 | drive. If you chose to build PARIDE support into your kernel, you | ||
239 | may answer Y here to build in the protocol driver, otherwise you | ||
240 | should answer M to build it as a loadable module. The module will be | ||
241 | called friq. You must also have a high-level driver for the type | ||
242 | of device that you want to support. | ||
243 | |||
244 | config PARIDE_FRPW | ||
245 | tristate "FreeCom power protocol" | ||
246 | depends on PARIDE | ||
247 | help | ||
248 | This option enables support for the Freecom power parallel port IDE | ||
249 | protocol. If you chose to build PARIDE support into your kernel, you | ||
250 | may answer Y here to build in the protocol driver, otherwise you | ||
251 | should answer M to build it as a loadable module. The module will be | ||
252 | called frpw. You must also have a high-level driver for the type | ||
253 | of device that you want to support. | ||
254 | |||
255 | config PARIDE_KBIC | ||
256 | tristate "KingByte KBIC-951A/971A protocols" | ||
257 | depends on PARIDE | ||
258 | help | ||
259 | This option enables support for the KBIC-951A and KBIC-971A parallel | ||
260 | port IDE protocols from KingByte Information Corp. KingByte's | ||
261 | adapters appear in many no-name portable disk and CD-ROM products, | ||
262 | especially in Europe. If you chose to build PARIDE support into your | ||
263 | kernel, you may answer Y here to build in the protocol driver, | ||
264 | otherwise you should answer M to build it as a loadable module. The | ||
265 | module will be called kbic. You must also have a high-level driver | ||
266 | for the type of device that you want to support. | ||
267 | |||
268 | config PARIDE_KTTI | ||
269 | tristate "KT PHd protocol" | ||
270 | depends on PARIDE | ||
271 | help | ||
272 | This option enables support for the "PHd" parallel port IDE protocol | ||
273 | from KT Technology. This is a simple (low speed) adapter that is | ||
274 | used in some 2.5" portable hard drives. If you chose to build PARIDE | ||
275 | support into your kernel, you may answer Y here to build in the | ||
276 | protocol driver, otherwise you should answer M to build it as a | ||
277 | loadable module. The module will be called ktti. You must also | ||
278 | have a high-level driver for the type of device that you want to | ||
279 | support. | ||
280 | |||
281 | config PARIDE_ON20 | ||
282 | tristate "OnSpec 90c20 protocol" | ||
283 | depends on PARIDE | ||
284 | help | ||
285 | This option enables support for the (obsolete) 90c20 parallel port | ||
286 | IDE protocol from OnSpec (often marketed under the ValuStore brand | ||
287 | name). If you chose to build PARIDE support into your kernel, you | ||
288 | may answer Y here to build in the protocol driver, otherwise you | ||
289 | should answer M to build it as a loadable module. The module will | ||
290 | be called on20. You must also have a high-level driver for the | ||
291 | type of device that you want to support. | ||
292 | |||
293 | config PARIDE_ON26 | ||
294 | tristate "OnSpec 90c26 protocol" | ||
295 | depends on PARIDE | ||
296 | help | ||
297 | This option enables support for the 90c26 parallel port IDE protocol | ||
298 | from OnSpec Electronics (often marketed under the ValuStore brand | ||
299 | name). If you chose to build PARIDE support into your kernel, you | ||
300 | may answer Y here to build in the protocol driver, otherwise you | ||
301 | should answer M to build it as a loadable module. The module will be | ||
302 | called on26. You must also have a high-level driver for the type | ||
303 | of device that you want to support. | ||
304 | |||
305 | # | ||
diff --git a/drivers/block/paride/Makefile b/drivers/block/paride/Makefile new file mode 100644 index 000000000000..a539e004bb7a --- /dev/null +++ b/drivers/block/paride/Makefile | |||
@@ -0,0 +1,28 @@ | |||
1 | # | ||
2 | # Makefile for Parallel port IDE device drivers. | ||
3 | # | ||
4 | # 7 October 2000, Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> | ||
5 | # Rewritten to use lists instead of if-statements. | ||
6 | # | ||
7 | |||
8 | obj-$(CONFIG_PARIDE) += paride.o | ||
9 | obj-$(CONFIG_PARIDE_ATEN) += aten.o | ||
10 | obj-$(CONFIG_PARIDE_BPCK) += bpck.o | ||
11 | obj-$(CONFIG_PARIDE_COMM) += comm.o | ||
12 | obj-$(CONFIG_PARIDE_DSTR) += dstr.o | ||
13 | obj-$(CONFIG_PARIDE_KBIC) += kbic.o | ||
14 | obj-$(CONFIG_PARIDE_EPAT) += epat.o | ||
15 | obj-$(CONFIG_PARIDE_EPIA) += epia.o | ||
16 | obj-$(CONFIG_PARIDE_FRPW) += frpw.o | ||
17 | obj-$(CONFIG_PARIDE_FRIQ) += friq.o | ||
18 | obj-$(CONFIG_PARIDE_FIT2) += fit2.o | ||
19 | obj-$(CONFIG_PARIDE_FIT3) += fit3.o | ||
20 | obj-$(CONFIG_PARIDE_ON20) += on20.o | ||
21 | obj-$(CONFIG_PARIDE_ON26) += on26.o | ||
22 | obj-$(CONFIG_PARIDE_KTTI) += ktti.o | ||
23 | obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o | ||
24 | obj-$(CONFIG_PARIDE_PD) += pd.o | ||
25 | obj-$(CONFIG_PARIDE_PCD) += pcd.o | ||
26 | obj-$(CONFIG_PARIDE_PF) += pf.o | ||
27 | obj-$(CONFIG_PARIDE_PT) += pt.o | ||
28 | obj-$(CONFIG_PARIDE_PG) += pg.o | ||
diff --git a/drivers/block/paride/Transition-notes b/drivers/block/paride/Transition-notes new file mode 100644 index 000000000000..70374907c020 --- /dev/null +++ b/drivers/block/paride/Transition-notes | |||
@@ -0,0 +1,128 @@ | |||
1 | Lemma 1: | ||
2 | If ps_tq is scheduled, ps_tq_active is 1. ps_tq_int() can be called | ||
3 | only when ps_tq_active is 1. | ||
4 | Proof: All assignments to ps_tq_active and all scheduling of ps_tq happen | ||
5 | under ps_spinlock. There are three places where that can happen: | ||
6 | one in ps_set_intr() (A) and two in ps_tq_int() (B and C). | ||
7 | Consider the sequnce of these events. A can not be preceded by | ||
8 | anything except B, since it is under if (!ps_tq_active) under | ||
9 | ps_spinlock. C is always preceded by B, since we can't reach it | ||
10 | other than through B and we don't drop ps_spinlock between them. | ||
11 | IOW, the sequence is A?(BA|BC|B)*. OTOH, number of B can not exceed | ||
12 | the sum of numbers of A and C, since each call of ps_tq_int() is | ||
13 | the result of ps_tq execution. Therefore, the sequence starts with | ||
14 | A and each B is preceded by either A or C. Moments when we enter | ||
15 | ps_tq_int() are sandwiched between {A,C} and B in that sequence, | ||
16 | since at any time number of B can not exceed the number of these | ||
17 | moments which, in turn, can not exceed the number of A and C. | ||
18 | In other words, the sequence of events is (A or C set ps_tq_active to | ||
19 | 1 and schedule ps_tq, ps_tq is executed, ps_tq_int() is entered, | ||
20 | B resets ps_tq_active)*. | ||
21 | |||
22 | |||
23 | consider the following area: | ||
24 | * in do_pd_request1(): to calls of pi_do_claimed() and return in | ||
25 | case when pd_req is NULL. | ||
26 | * in next_request(): to call of do_pd_request1() | ||
27 | * in do_pd_read(): to call of ps_set_intr() | ||
28 | * in do_pd_read_start(): to calls of pi_do_claimed(), next_request() | ||
29 | and ps_set_intr() | ||
30 | * in do_pd_read_drq(): to calls of pi_do_claimed() and next_request() | ||
31 | * in do_pd_write(): to call of ps_set_intr() | ||
32 | * in do_pd_write_start(): to calls of pi_do_claimed(), next_request() | ||
33 | and ps_set_intr() | ||
34 | * in do_pd_write_done(): to calls of pi_do_claimed() and next_request() | ||
35 | * in ps_set_intr(): to check for ps_tq_active and to scheduling | ||
36 | ps_tq if ps_tq_active was 0. | ||
37 | * in ps_tq_int(): from the moment when we get ps_spinlock() to the | ||
38 | return, call of con() or scheduling ps_tq. | ||
39 | * in pi_schedule_claimed() when called from pi_do_claimed() called from | ||
40 | pd.c, everything until returning 1 or setting or setting ->claim_cont | ||
41 | on the path that returns 0 | ||
42 | * in pi_do_claimed() when called from pd.c, everything until the call | ||
43 | of pi_do_claimed() plus the everything until the call of cont() if | ||
44 | pi_do_claimed() has returned 1. | ||
45 | * in pi_wake_up() called for PIA that belongs to pd.c, everything from | ||
46 | the moment when pi_spinlock has been acquired. | ||
47 | |||
48 | Lemma 2: | ||
49 | 1) at any time at most one thread of execution can be in that area or | ||
50 | be preempted there. | ||
51 | 2) When there is such a thread, pd_busy is set or pd_lock is held by | ||
52 | that thread. | ||
53 | 3) When there is such a thread, ps_tq_active is 0 or ps_spinlock is | ||
54 | held by that thread. | ||
55 | 4) When there is such a thread, all PIA belonging to pd.c have NULL | ||
56 | ->claim_cont or pi_spinlock is held by thread in question. | ||
57 | |||
58 | Proof: consider the first moment when the above is not true. | ||
59 | |||
60 | (1) can become not true if some thread enters that area while another is there. | ||
61 | a) do_pd_request1() can be called from next_request() or do_pd_request() | ||
62 | In the first case the thread was already in the area. In the second, | ||
63 | the thread was holding pd_lock and found pd_busy not set, which would | ||
64 | mean that (2) was already not true. | ||
65 | b) ps_set_intr() and pi_schedule_claimed() can be called only from the | ||
66 | area. | ||
67 | c) pi_do_claimed() is called by pd.c only from the area. | ||
68 | d) ps_tq_int() can enter the area only when the thread is holding | ||
69 | ps_spinlock and ps_tq_active is 1 (due to Lemma 1). It means that | ||
70 | (3) was already not true. | ||
71 | e) do_pd_{read,write}* could be called only from the area. The only | ||
72 | case that needs consideration is call from pi_wake_up() and there | ||
73 | we would have to be called for the PIA that got ->claimed_cont | ||
74 | from pd.c. That could happen only if pi_do_claimed() had been | ||
75 | called from pd.c for that PIA, which happens only for PIA belonging | ||
76 | to pd.c. | ||
77 | f) pi_wake_up() can enter the area only when the thread is holding | ||
78 | pi_spinlock and ->claimed_cont is non-NULL for PIA belonging to | ||
79 | pd.c. It means that (4) was already not true. | ||
80 | |||
81 | (2) can become not true only when pd_lock is released by the thread in question. | ||
82 | Indeed, pd_busy is reset only in the area and thread that resets | ||
83 | it is holding pd_lock. The only place within the area where we | ||
84 | release pd_lock is in pd_next_buf() (called from within the area). | ||
85 | But that code does not reset pd_busy, so pd_busy would have to be | ||
86 | 0 when pd_next_buf() had acquired pd_lock. If it become 0 while | ||
87 | we were acquiring the lock, (1) would be already false, since | ||
88 | the thread that had reset it would be in the area simulateously. | ||
89 | If it was 0 before we tried to acquire pd_lock, (2) would be | ||
90 | already false. | ||
91 | |||
92 | For similar reasons, (3) can become not true only when ps_spinlock is released | ||
93 | by the thread in question. However, all such places within the area are right | ||
94 | after resetting ps_tq_active to 0. | ||
95 | |||
96 | (4) is done the same way - all places where we release pi_spinlock within | ||
97 | the area are either after resetting ->claimed_cont to NULL while holding | ||
98 | pi_spinlock, or after not tocuhing ->claimed_cont since acquiring pi_spinlock | ||
99 | also in the area. The only place where ->claimed_cont is made non-NULL is | ||
100 | in the area, under pi_spinlock and we do not release it until after leaving | ||
101 | the area. | ||
102 | |||
103 | QED. | ||
104 | |||
105 | |||
106 | Corollary 1: ps_tq_active can be killed. Indeed, the only place where we | ||
107 | check its value is in ps_set_intr() and if it had been non-zero at that | ||
108 | point, we would have violated either (2.1) (if it was set while ps_set_intr() | ||
109 | was acquiring ps_spinlock) or (2.3) (if it was set when we started to | ||
110 | acquire ps_spinlock). | ||
111 | |||
112 | Corollary 2: ps_spinlock can be killed. Indeed, Lemma 1 and Lemma 2 show | ||
113 | that the only possible contention is between scheduling ps_tq followed by | ||
114 | immediate release of spinlock and beginning of execution of ps_tq on | ||
115 | another CPU. | ||
116 | |||
117 | Corollary 3: assignment to pd_busy in do_pd_read_start() and do_pd_write_start() | ||
118 | can be killed. Indeed, we are not holding pd_lock and thus pd_busy is already | ||
119 | 1 here. | ||
120 | |||
121 | Corollary 4: in ps_tq_int() uses of con can be replaced with uses of | ||
122 | ps_continuation, since the latter is changed only from the area. | ||
123 | We don't need to reset it to NULL, since we are guaranteed that there | ||
124 | will be a call of ps_set_intr() before we look at ps_continuation again. | ||
125 | We can remove the check for ps_continuation being NULL for the same | ||
126 | reason - the value is guaranteed to be set by the last ps_set_intr() and | ||
127 | we never pass it NULL. Assignements in the beginning of ps_set_intr() | ||
128 | can be taken to callers as long as they remain within the area. | ||
diff --git a/drivers/block/paride/aten.c b/drivers/block/paride/aten.c new file mode 100644 index 000000000000..c4d696d43dc1 --- /dev/null +++ b/drivers/block/paride/aten.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | aten.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | aten.c is a low-level protocol driver for the ATEN EH-100 | ||
6 | parallel port adapter. The EH-100 supports 4-bit and 8-bit | ||
7 | modes only. There is also an EH-132 which supports EPP mode | ||
8 | transfers. The EH-132 is not yet supported. | ||
9 | |||
10 | */ | ||
11 | |||
12 | /* Changes: | ||
13 | |||
14 | 1.01 GRG 1998.05.05 init_proto, release_proto | ||
15 | |||
16 | */ | ||
17 | |||
18 | #define ATEN_VERSION "1.01" | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/wait.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include "paride.h" | ||
29 | |||
30 | #define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88) | ||
31 | |||
32 | /* cont = 0 - access the IDE register file | ||
33 | cont = 1 - access the IDE command set | ||
34 | */ | ||
35 | |||
36 | static int cont_map[2] = { 0x08, 0x20 }; | ||
37 | |||
38 | static void aten_write_regr( PIA *pi, int cont, int regr, int val) | ||
39 | |||
40 | { int r; | ||
41 | |||
42 | r = regr + cont_map[cont] + 0x80; | ||
43 | |||
44 | w0(r); w2(0xe); w2(6); w0(val); w2(7); w2(6); w2(0xc); | ||
45 | } | ||
46 | |||
47 | static int aten_read_regr( PIA *pi, int cont, int regr ) | ||
48 | |||
49 | { int a, b, r; | ||
50 | |||
51 | r = regr + cont_map[cont] + 0x40; | ||
52 | |||
53 | switch (pi->mode) { | ||
54 | |||
55 | case 0: w0(r); w2(0xe); w2(6); | ||
56 | w2(7); w2(6); w2(0); | ||
57 | a = r1(); w0(0x10); b = r1(); w2(0xc); | ||
58 | return j44(a,b); | ||
59 | |||
60 | case 1: r |= 0x10; | ||
61 | w0(r); w2(0xe); w2(6); w0(0xff); | ||
62 | w2(0x27); w2(0x26); w2(0x20); | ||
63 | a = r0(); | ||
64 | w2(0x26); w2(0xc); | ||
65 | return a; | ||
66 | } | ||
67 | return -1; | ||
68 | } | ||
69 | |||
70 | static void aten_read_block( PIA *pi, char * buf, int count ) | ||
71 | |||
72 | { int k, a, b, c, d; | ||
73 | |||
74 | switch (pi->mode) { | ||
75 | |||
76 | case 0: w0(0x48); w2(0xe); w2(6); | ||
77 | for (k=0;k<count/2;k++) { | ||
78 | w2(7); w2(6); w2(2); | ||
79 | a = r1(); w0(0x58); b = r1(); | ||
80 | w2(0); d = r1(); w0(0x48); c = r1(); | ||
81 | buf[2*k] = j44(c,d); | ||
82 | buf[2*k+1] = j44(a,b); | ||
83 | } | ||
84 | w2(0xc); | ||
85 | break; | ||
86 | |||
87 | case 1: w0(0x58); w2(0xe); w2(6); | ||
88 | for (k=0;k<count/2;k++) { | ||
89 | w2(0x27); w2(0x26); w2(0x22); | ||
90 | a = r0(); w2(0x20); b = r0(); | ||
91 | buf[2*k] = b; buf[2*k+1] = a; | ||
92 | } | ||
93 | w2(0x26); w2(0xc); | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static void aten_write_block( PIA *pi, char * buf, int count ) | ||
99 | |||
100 | { int k; | ||
101 | |||
102 | w0(0x88); w2(0xe); w2(6); | ||
103 | for (k=0;k<count/2;k++) { | ||
104 | w0(buf[2*k+1]); w2(0xe); w2(6); | ||
105 | w0(buf[2*k]); w2(7); w2(6); | ||
106 | } | ||
107 | w2(0xc); | ||
108 | } | ||
109 | |||
110 | static void aten_connect ( PIA *pi ) | ||
111 | |||
112 | { pi->saved_r0 = r0(); | ||
113 | pi->saved_r2 = r2(); | ||
114 | w2(0xc); | ||
115 | } | ||
116 | |||
117 | static void aten_disconnect ( PIA *pi ) | ||
118 | |||
119 | { w0(pi->saved_r0); | ||
120 | w2(pi->saved_r2); | ||
121 | } | ||
122 | |||
123 | static void aten_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
124 | |||
125 | { char *mode_string[2] = {"4-bit","8-bit"}; | ||
126 | |||
127 | printk("%s: aten %s, ATEN EH-100 at 0x%x, ", | ||
128 | pi->device,ATEN_VERSION,pi->port); | ||
129 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
130 | mode_string[pi->mode],pi->delay); | ||
131 | |||
132 | } | ||
133 | |||
134 | static struct pi_protocol aten = { | ||
135 | .owner = THIS_MODULE, | ||
136 | .name = "aten", | ||
137 | .max_mode = 2, | ||
138 | .epp_first = 2, | ||
139 | .default_delay = 1, | ||
140 | .max_units = 1, | ||
141 | .write_regr = aten_write_regr, | ||
142 | .read_regr = aten_read_regr, | ||
143 | .write_block = aten_write_block, | ||
144 | .read_block = aten_read_block, | ||
145 | .connect = aten_connect, | ||
146 | .disconnect = aten_disconnect, | ||
147 | .log_adapter = aten_log_adapter, | ||
148 | }; | ||
149 | |||
150 | static int __init aten_init(void) | ||
151 | { | ||
152 | return pi_register(&aten)-1; | ||
153 | } | ||
154 | |||
155 | static void __exit aten_exit(void) | ||
156 | { | ||
157 | pi_unregister( &aten ); | ||
158 | } | ||
159 | |||
160 | MODULE_LICENSE("GPL"); | ||
161 | module_init(aten_init) | ||
162 | module_exit(aten_exit) | ||
diff --git a/drivers/block/paride/bpck.c b/drivers/block/paride/bpck.c new file mode 100644 index 000000000000..d462ff6b139d --- /dev/null +++ b/drivers/block/paride/bpck.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | bpck.c (c) 1996-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | bpck.c is a low-level protocol driver for the MicroSolutions | ||
6 | "backpack" parallel port IDE adapter. | ||
7 | |||
8 | */ | ||
9 | |||
10 | /* Changes: | ||
11 | |||
12 | 1.01 GRG 1998.05.05 init_proto, release_proto, pi->delay | ||
13 | 1.02 GRG 1998.08.15 default pi->delay returned to 4 | ||
14 | |||
15 | */ | ||
16 | |||
17 | #define BPCK_VERSION "1.02" | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/wait.h> | ||
25 | #include <asm/io.h> | ||
26 | |||
27 | #include "paride.h" | ||
28 | |||
29 | #undef r2 | ||
30 | #undef w2 | ||
31 | |||
32 | #define PC pi->private | ||
33 | #define r2() (PC=(in_p(2) & 0xff)) | ||
34 | #define w2(byte) {out_p(2,byte); PC = byte;} | ||
35 | #define t2(pat) {PC ^= pat; out_p(2,PC);} | ||
36 | #define e2() {PC &= 0xfe; out_p(2,PC);} | ||
37 | #define o2() {PC |= 1; out_p(2,PC);} | ||
38 | |||
39 | #define j44(l,h) (((l>>3)&0x7)|((l>>4)&0x8)|((h<<1)&0x70)|(h&0x80)) | ||
40 | |||
41 | /* cont = 0 - access the IDE register file | ||
42 | cont = 1 - access the IDE command set | ||
43 | cont = 2 - use internal bpck register addressing | ||
44 | */ | ||
45 | |||
46 | static int cont_map[3] = { 0x40, 0x48, 0 }; | ||
47 | |||
48 | static int bpck_read_regr( PIA *pi, int cont, int regr ) | ||
49 | |||
50 | { int r, l, h; | ||
51 | |||
52 | r = regr + cont_map[cont]; | ||
53 | |||
54 | switch (pi->mode) { | ||
55 | |||
56 | case 0: w0(r & 0xf); w0(r); t2(2); t2(4); | ||
57 | l = r1(); | ||
58 | t2(4); | ||
59 | h = r1(); | ||
60 | return j44(l,h); | ||
61 | |||
62 | case 1: w0(r & 0xf); w0(r); t2(2); | ||
63 | e2(); t2(0x20); | ||
64 | t2(4); h = r0(); | ||
65 | t2(1); t2(0x20); | ||
66 | return h; | ||
67 | |||
68 | case 2: | ||
69 | case 3: | ||
70 | case 4: w0(r); w2(9); w2(0); w2(0x20); | ||
71 | h = r4(); | ||
72 | w2(0); | ||
73 | return h; | ||
74 | |||
75 | } | ||
76 | return -1; | ||
77 | } | ||
78 | |||
79 | static void bpck_write_regr( PIA *pi, int cont, int regr, int val ) | ||
80 | |||
81 | { int r; | ||
82 | |||
83 | r = regr + cont_map[cont]; | ||
84 | |||
85 | switch (pi->mode) { | ||
86 | |||
87 | case 0: | ||
88 | case 1: w0(r); | ||
89 | t2(2); | ||
90 | w0(val); | ||
91 | o2(); t2(4); t2(1); | ||
92 | break; | ||
93 | |||
94 | case 2: | ||
95 | case 3: | ||
96 | case 4: w0(r); w2(9); w2(0); | ||
97 | w0(val); w2(1); w2(3); w2(0); | ||
98 | break; | ||
99 | |||
100 | } | ||
101 | } | ||
102 | |||
103 | /* These macros access the bpck registers in native addressing */ | ||
104 | |||
105 | #define WR(r,v) bpck_write_regr(pi,2,r,v) | ||
106 | #define RR(r) (bpck_read_regr(pi,2,r)) | ||
107 | |||
108 | static void bpck_write_block( PIA *pi, char * buf, int count ) | ||
109 | |||
110 | { int i; | ||
111 | |||
112 | switch (pi->mode) { | ||
113 | |||
114 | case 0: WR(4,0x40); | ||
115 | w0(0x40); t2(2); t2(1); | ||
116 | for (i=0;i<count;i++) { w0(buf[i]); t2(4); } | ||
117 | WR(4,0); | ||
118 | break; | ||
119 | |||
120 | case 1: WR(4,0x50); | ||
121 | w0(0x40); t2(2); t2(1); | ||
122 | for (i=0;i<count;i++) { w0(buf[i]); t2(4); } | ||
123 | WR(4,0x10); | ||
124 | break; | ||
125 | |||
126 | case 2: WR(4,0x48); | ||
127 | w0(0x40); w2(9); w2(0); w2(1); | ||
128 | for (i=0;i<count;i++) w4(buf[i]); | ||
129 | w2(0); | ||
130 | WR(4,8); | ||
131 | break; | ||
132 | |||
133 | case 3: WR(4,0x48); | ||
134 | w0(0x40); w2(9); w2(0); w2(1); | ||
135 | for (i=0;i<count/2;i++) w4w(((u16 *)buf)[i]); | ||
136 | w2(0); | ||
137 | WR(4,8); | ||
138 | break; | ||
139 | |||
140 | case 4: WR(4,0x48); | ||
141 | w0(0x40); w2(9); w2(0); w2(1); | ||
142 | for (i=0;i<count/4;i++) w4l(((u32 *)buf)[i]); | ||
143 | w2(0); | ||
144 | WR(4,8); | ||
145 | break; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void bpck_read_block( PIA *pi, char * buf, int count ) | ||
150 | |||
151 | { int i, l, h; | ||
152 | |||
153 | switch (pi->mode) { | ||
154 | |||
155 | case 0: WR(4,0x40); | ||
156 | w0(0x40); t2(2); | ||
157 | for (i=0;i<count;i++) { | ||
158 | t2(4); l = r1(); | ||
159 | t2(4); h = r1(); | ||
160 | buf[i] = j44(l,h); | ||
161 | } | ||
162 | WR(4,0); | ||
163 | break; | ||
164 | |||
165 | case 1: WR(4,0x50); | ||
166 | w0(0x40); t2(2); t2(0x20); | ||
167 | for(i=0;i<count;i++) { t2(4); buf[i] = r0(); } | ||
168 | t2(1); t2(0x20); | ||
169 | WR(4,0x10); | ||
170 | break; | ||
171 | |||
172 | case 2: WR(4,0x48); | ||
173 | w0(0x40); w2(9); w2(0); w2(0x20); | ||
174 | for (i=0;i<count;i++) buf[i] = r4(); | ||
175 | w2(0); | ||
176 | WR(4,8); | ||
177 | break; | ||
178 | |||
179 | case 3: WR(4,0x48); | ||
180 | w0(0x40); w2(9); w2(0); w2(0x20); | ||
181 | for (i=0;i<count/2;i++) ((u16 *)buf)[i] = r4w(); | ||
182 | w2(0); | ||
183 | WR(4,8); | ||
184 | break; | ||
185 | |||
186 | case 4: WR(4,0x48); | ||
187 | w0(0x40); w2(9); w2(0); w2(0x20); | ||
188 | for (i=0;i<count/4;i++) ((u32 *)buf)[i] = r4l(); | ||
189 | w2(0); | ||
190 | WR(4,8); | ||
191 | break; | ||
192 | |||
193 | } | ||
194 | } | ||
195 | |||
196 | static int bpck_probe_unit ( PIA *pi ) | ||
197 | |||
198 | { int o1, o0, f7, id; | ||
199 | int t, s; | ||
200 | |||
201 | id = pi->unit; | ||
202 | s = 0; | ||
203 | w2(4); w2(0xe); r2(); t2(2); | ||
204 | o1 = r1()&0xf8; | ||
205 | o0 = r0(); | ||
206 | w0(255-id); w2(4); w0(id); | ||
207 | t2(8); t2(8); t2(8); | ||
208 | t2(2); t = r1()&0xf8; | ||
209 | f7 = ((id % 8) == 7); | ||
210 | if ((f7) || (t != o1)) { t2(2); s = r1()&0xf8; } | ||
211 | if ((t == o1) && ((!f7) || (s == o1))) { | ||
212 | w2(0x4c); w0(o0); | ||
213 | return 0; | ||
214 | } | ||
215 | t2(8); w0(0); t2(2); w2(0x4c); w0(o0); | ||
216 | return 1; | ||
217 | } | ||
218 | |||
219 | static void bpck_connect ( PIA *pi ) | ||
220 | |||
221 | { pi->saved_r0 = r0(); | ||
222 | w0(0xff-pi->unit); w2(4); w0(pi->unit); | ||
223 | t2(8); t2(8); t2(8); | ||
224 | t2(2); t2(2); | ||
225 | |||
226 | switch (pi->mode) { | ||
227 | |||
228 | case 0: t2(8); WR(4,0); | ||
229 | break; | ||
230 | |||
231 | case 1: t2(8); WR(4,0x10); | ||
232 | break; | ||
233 | |||
234 | case 2: | ||
235 | case 3: | ||
236 | case 4: w2(0); WR(4,8); | ||
237 | break; | ||
238 | |||
239 | } | ||
240 | |||
241 | WR(5,8); | ||
242 | |||
243 | if (pi->devtype == PI_PCD) { | ||
244 | WR(0x46,0x10); /* fiddle with ESS logic ??? */ | ||
245 | WR(0x4c,0x38); | ||
246 | WR(0x4d,0x88); | ||
247 | WR(0x46,0xa0); | ||
248 | WR(0x41,0); | ||
249 | WR(0x4e,8); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static void bpck_disconnect ( PIA *pi ) | ||
254 | |||
255 | { w0(0); | ||
256 | if (pi->mode >= 2) { w2(9); w2(0); } else t2(2); | ||
257 | w2(0x4c); w0(pi->saved_r0); | ||
258 | } | ||
259 | |||
260 | static void bpck_force_spp ( PIA *pi ) | ||
261 | |||
262 | /* This fakes the EPP protocol to turn off EPP ... */ | ||
263 | |||
264 | { pi->saved_r0 = r0(); | ||
265 | w0(0xff-pi->unit); w2(4); w0(pi->unit); | ||
266 | t2(8); t2(8); t2(8); | ||
267 | t2(2); t2(2); | ||
268 | |||
269 | w2(0); | ||
270 | w0(4); w2(9); w2(0); | ||
271 | w0(0); w2(1); w2(3); w2(0); | ||
272 | w0(0); w2(9); w2(0); | ||
273 | w2(0x4c); w0(pi->saved_r0); | ||
274 | } | ||
275 | |||
276 | #define TEST_LEN 16 | ||
277 | |||
278 | static int bpck_test_proto( PIA *pi, char * scratch, int verbose ) | ||
279 | |||
280 | { int i, e, l, h, om; | ||
281 | char buf[TEST_LEN]; | ||
282 | |||
283 | bpck_force_spp(pi); | ||
284 | |||
285 | switch (pi->mode) { | ||
286 | |||
287 | case 0: bpck_connect(pi); | ||
288 | WR(0x13,0x7f); | ||
289 | w0(0x13); t2(2); | ||
290 | for(i=0;i<TEST_LEN;i++) { | ||
291 | t2(4); l = r1(); | ||
292 | t2(4); h = r1(); | ||
293 | buf[i] = j44(l,h); | ||
294 | } | ||
295 | bpck_disconnect(pi); | ||
296 | break; | ||
297 | |||
298 | case 1: bpck_connect(pi); | ||
299 | WR(0x13,0x7f); | ||
300 | w0(0x13); t2(2); t2(0x20); | ||
301 | for(i=0;i<TEST_LEN;i++) { t2(4); buf[i] = r0(); } | ||
302 | t2(1); t2(0x20); | ||
303 | bpck_disconnect(pi); | ||
304 | break; | ||
305 | |||
306 | case 2: | ||
307 | case 3: | ||
308 | case 4: om = pi->mode; | ||
309 | pi->mode = 0; | ||
310 | bpck_connect(pi); | ||
311 | WR(7,3); | ||
312 | WR(4,8); | ||
313 | bpck_disconnect(pi); | ||
314 | |||
315 | pi->mode = om; | ||
316 | bpck_connect(pi); | ||
317 | w0(0x13); w2(9); w2(1); w0(0); w2(3); w2(0); w2(0xe0); | ||
318 | |||
319 | switch (pi->mode) { | ||
320 | case 2: for (i=0;i<TEST_LEN;i++) buf[i] = r4(); | ||
321 | break; | ||
322 | case 3: for (i=0;i<TEST_LEN/2;i++) ((u16 *)buf)[i] = r4w(); | ||
323 | break; | ||
324 | case 4: for (i=0;i<TEST_LEN/4;i++) ((u32 *)buf)[i] = r4l(); | ||
325 | break; | ||
326 | } | ||
327 | |||
328 | w2(0); | ||
329 | WR(7,0); | ||
330 | bpck_disconnect(pi); | ||
331 | |||
332 | break; | ||
333 | |||
334 | } | ||
335 | |||
336 | if (verbose) { | ||
337 | printk("%s: bpck: 0x%x unit %d mode %d: ", | ||
338 | pi->device,pi->port,pi->unit,pi->mode); | ||
339 | for (i=0;i<TEST_LEN;i++) printk("%3d",buf[i]); | ||
340 | printk("\n"); | ||
341 | } | ||
342 | |||
343 | e = 0; | ||
344 | for (i=0;i<TEST_LEN;i++) if (buf[i] != (i+1)) e++; | ||
345 | return e; | ||
346 | } | ||
347 | |||
348 | static void bpck_read_eeprom ( PIA *pi, char * buf ) | ||
349 | |||
350 | { int i,j,k,n,p,v,f, om, od; | ||
351 | |||
352 | bpck_force_spp(pi); | ||
353 | |||
354 | om = pi->mode; od = pi->delay; | ||
355 | pi->mode = 0; pi->delay = 6; | ||
356 | |||
357 | bpck_connect(pi); | ||
358 | |||
359 | n = 0; | ||
360 | WR(4,0); | ||
361 | for (i=0;i<64;i++) { | ||
362 | WR(6,8); | ||
363 | WR(6,0xc); | ||
364 | p = 0x100; | ||
365 | for (k=0;k<9;k++) { | ||
366 | f = (((i + 0x180) & p) != 0) * 2; | ||
367 | WR(6,f+0xc); | ||
368 | WR(6,f+0xd); | ||
369 | WR(6,f+0xc); | ||
370 | p = (p >> 1); | ||
371 | } | ||
372 | for (j=0;j<2;j++) { | ||
373 | v = 0; | ||
374 | for (k=0;k<8;k++) { | ||
375 | WR(6,0xc); | ||
376 | WR(6,0xd); | ||
377 | WR(6,0xc); | ||
378 | f = RR(0); | ||
379 | v = 2*v + (f == 0x84); | ||
380 | } | ||
381 | buf[2*i+1-j] = v; | ||
382 | } | ||
383 | } | ||
384 | WR(6,8); | ||
385 | WR(6,0); | ||
386 | WR(5,8); | ||
387 | |||
388 | bpck_disconnect(pi); | ||
389 | |||
390 | if (om >= 2) { | ||
391 | bpck_connect(pi); | ||
392 | WR(7,3); | ||
393 | WR(4,8); | ||
394 | bpck_disconnect(pi); | ||
395 | } | ||
396 | |||
397 | pi->mode = om; pi->delay = od; | ||
398 | } | ||
399 | |||
400 | static int bpck_test_port ( PIA *pi ) /* check for 8-bit port */ | ||
401 | |||
402 | { int i, r, m; | ||
403 | |||
404 | w2(0x2c); i = r0(); w0(255-i); r = r0(); w0(i); | ||
405 | m = -1; | ||
406 | if (r == i) m = 2; | ||
407 | if (r == (255-i)) m = 0; | ||
408 | |||
409 | w2(0xc); i = r0(); w0(255-i); r = r0(); w0(i); | ||
410 | if (r != (255-i)) m = -1; | ||
411 | |||
412 | if (m == 0) { w2(6); w2(0xc); r = r0(); w0(0xaa); w0(r); w0(0xaa); } | ||
413 | if (m == 2) { w2(0x26); w2(0xc); } | ||
414 | |||
415 | if (m == -1) return 0; | ||
416 | return 5; | ||
417 | } | ||
418 | |||
419 | static void bpck_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
420 | |||
421 | { char *mode_string[5] = { "4-bit","8-bit","EPP-8", | ||
422 | "EPP-16","EPP-32" }; | ||
423 | |||
424 | #ifdef DUMP_EEPROM | ||
425 | int i; | ||
426 | #endif | ||
427 | |||
428 | bpck_read_eeprom(pi,scratch); | ||
429 | |||
430 | #ifdef DUMP_EEPROM | ||
431 | if (verbose) { | ||
432 | for(i=0;i<128;i++) | ||
433 | if ((scratch[i] < ' ') || (scratch[i] > '~')) | ||
434 | scratch[i] = '.'; | ||
435 | printk("%s: bpck EEPROM: %64.64s\n",pi->device,scratch); | ||
436 | printk("%s: %64.64s\n",pi->device,&scratch[64]); | ||
437 | } | ||
438 | #endif | ||
439 | |||
440 | printk("%s: bpck %s, backpack %8.8s unit %d", | ||
441 | pi->device,BPCK_VERSION,&scratch[110],pi->unit); | ||
442 | printk(" at 0x%x, mode %d (%s), delay %d\n",pi->port, | ||
443 | pi->mode,mode_string[pi->mode],pi->delay); | ||
444 | } | ||
445 | |||
446 | static struct pi_protocol bpck = { | ||
447 | .owner = THIS_MODULE, | ||
448 | .name = "bpck", | ||
449 | .max_mode = 5, | ||
450 | .epp_first = 2, | ||
451 | .default_delay = 4, | ||
452 | .max_units = 255, | ||
453 | .write_regr = bpck_write_regr, | ||
454 | .read_regr = bpck_read_regr, | ||
455 | .write_block = bpck_write_block, | ||
456 | .read_block = bpck_read_block, | ||
457 | .connect = bpck_connect, | ||
458 | .disconnect = bpck_disconnect, | ||
459 | .test_port = bpck_test_port, | ||
460 | .probe_unit = bpck_probe_unit, | ||
461 | .test_proto = bpck_test_proto, | ||
462 | .log_adapter = bpck_log_adapter, | ||
463 | }; | ||
464 | |||
465 | static int __init bpck_init(void) | ||
466 | { | ||
467 | return pi_register(&bpck)-1; | ||
468 | } | ||
469 | |||
470 | static void __exit bpck_exit(void) | ||
471 | { | ||
472 | pi_unregister(&bpck); | ||
473 | } | ||
474 | |||
475 | MODULE_LICENSE("GPL"); | ||
476 | module_init(bpck_init) | ||
477 | module_exit(bpck_exit) | ||
diff --git a/drivers/block/paride/bpck6.c b/drivers/block/paride/bpck6.c new file mode 100644 index 000000000000..08d858ad64db --- /dev/null +++ b/drivers/block/paride/bpck6.c | |||
@@ -0,0 +1,282 @@ | |||
1 | /* | ||
2 | backpack.c (c) 2001 Micro Solutions Inc. | ||
3 | Released under the terms of the GNU General Public license | ||
4 | |||
5 | backpack.c is a low-level protocol driver for the Micro Solutions | ||
6 | "BACKPACK" parallel port IDE adapter | ||
7 | (Works on Series 6 drives) | ||
8 | |||
9 | Written by: Ken Hahn (linux-dev@micro-solutions.com) | ||
10 | Clive Turvey (linux-dev@micro-solutions.com) | ||
11 | |||
12 | */ | ||
13 | |||
14 | /* | ||
15 | This is Ken's linux wrapper for the PPC library | ||
16 | Version 1.0.0 is the backpack driver for which source is not available | ||
17 | Version 2.0.0 is the first to have source released | ||
18 | Version 2.0.1 is the "Cox-ified" source code | ||
19 | Version 2.0.2 - fixed version string usage, and made ppc functions static | ||
20 | */ | ||
21 | |||
22 | |||
23 | /* PARAMETERS */ | ||
24 | static int verbose; /* set this to 1 to see debugging messages and whatnot */ | ||
25 | |||
26 | #define BACKPACK_VERSION "2.0.2" | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <asm/io.h> | ||
34 | |||
35 | #if defined(CONFIG_PARPORT_MODULE)||defined(CONFIG_PARPORT) | ||
36 | #include <linux/parport.h> | ||
37 | #endif | ||
38 | |||
39 | #include "ppc6lnx.c" | ||
40 | #include "paride.h" | ||
41 | |||
42 | |||
43 | |||
44 | #define PPCSTRUCT(pi) ((Interface *)(pi->private)) | ||
45 | |||
46 | /****************************************************************/ | ||
47 | /* | ||
48 | ATAPI CDROM DRIVE REGISTERS | ||
49 | */ | ||
50 | #define ATAPI_DATA 0 /* data port */ | ||
51 | #define ATAPI_ERROR 1 /* error register (read) */ | ||
52 | #define ATAPI_FEATURES 1 /* feature register (write) */ | ||
53 | #define ATAPI_INT_REASON 2 /* interrupt reason register */ | ||
54 | #define ATAPI_COUNT_LOW 4 /* byte count register (low) */ | ||
55 | #define ATAPI_COUNT_HIGH 5 /* byte count register (high) */ | ||
56 | #define ATAPI_DRIVE_SEL 6 /* drive select register */ | ||
57 | #define ATAPI_STATUS 7 /* status port (read) */ | ||
58 | #define ATAPI_COMMAND 7 /* command port (write) */ | ||
59 | #define ATAPI_ALT_STATUS 0x0e /* alternate status reg (read) */ | ||
60 | #define ATAPI_DEVICE_CONTROL 0x0e /* device control (write) */ | ||
61 | /****************************************************************/ | ||
62 | |||
63 | static int bpck6_read_regr(PIA *pi, int cont, int reg) | ||
64 | { | ||
65 | unsigned int out; | ||
66 | |||
67 | /* check for bad settings */ | ||
68 | if (reg<0 || reg>7 || cont<0 || cont>2) | ||
69 | { | ||
70 | return(-1); | ||
71 | } | ||
72 | out=ppc6_rd_port(PPCSTRUCT(pi),cont?reg|8:reg); | ||
73 | return(out); | ||
74 | } | ||
75 | |||
76 | static void bpck6_write_regr(PIA *pi, int cont, int reg, int val) | ||
77 | { | ||
78 | /* check for bad settings */ | ||
79 | if (reg>=0 && reg<=7 && cont>=0 && cont<=1) | ||
80 | { | ||
81 | ppc6_wr_port(PPCSTRUCT(pi),cont?reg|8:reg,(u8)val); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | static void bpck6_write_block( PIA *pi, char * buf, int len ) | ||
86 | { | ||
87 | ppc6_wr_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1); | ||
88 | } | ||
89 | |||
90 | static void bpck6_read_block( PIA *pi, char * buf, int len ) | ||
91 | { | ||
92 | ppc6_rd_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1); | ||
93 | } | ||
94 | |||
95 | static void bpck6_connect ( PIA *pi ) | ||
96 | { | ||
97 | if(verbose) | ||
98 | { | ||
99 | printk(KERN_DEBUG "connect\n"); | ||
100 | } | ||
101 | |||
102 | if(pi->mode >=2) | ||
103 | { | ||
104 | PPCSTRUCT(pi)->mode=4+pi->mode-2; | ||
105 | } | ||
106 | else if(pi->mode==1) | ||
107 | { | ||
108 | PPCSTRUCT(pi)->mode=3; | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | PPCSTRUCT(pi)->mode=1; | ||
113 | } | ||
114 | |||
115 | ppc6_open(PPCSTRUCT(pi)); | ||
116 | ppc6_wr_extout(PPCSTRUCT(pi),0x3); | ||
117 | } | ||
118 | |||
119 | static void bpck6_disconnect ( PIA *pi ) | ||
120 | { | ||
121 | if(verbose) | ||
122 | { | ||
123 | printk("disconnect\n"); | ||
124 | } | ||
125 | ppc6_wr_extout(PPCSTRUCT(pi),0x0); | ||
126 | ppc6_close(PPCSTRUCT(pi)); | ||
127 | } | ||
128 | |||
129 | static int bpck6_test_port ( PIA *pi ) /* check for 8-bit port */ | ||
130 | { | ||
131 | if(verbose) | ||
132 | { | ||
133 | printk(KERN_DEBUG "PARPORT indicates modes=%x for lp=0x%lx\n", | ||
134 | ((struct pardevice*)(pi->pardev))->port->modes, | ||
135 | ((struct pardevice *)(pi->pardev))->port->base); | ||
136 | } | ||
137 | |||
138 | /*copy over duplicate stuff.. initialize state info*/ | ||
139 | PPCSTRUCT(pi)->ppc_id=pi->unit; | ||
140 | PPCSTRUCT(pi)->lpt_addr=pi->port; | ||
141 | |||
142 | #ifdef CONFIG_PARPORT_PC_MODULE | ||
143 | #define CONFIG_PARPORT_PC | ||
144 | #endif | ||
145 | |||
146 | #ifdef CONFIG_PARPORT_PC | ||
147 | /* look at the parport device to see if what modes we can use */ | ||
148 | if(((struct pardevice *)(pi->pardev))->port->modes & | ||
149 | (PARPORT_MODE_EPP) | ||
150 | ) | ||
151 | { | ||
152 | return 5; /* Can do EPP*/ | ||
153 | } | ||
154 | else if(((struct pardevice *)(pi->pardev))->port->modes & | ||
155 | (PARPORT_MODE_TRISTATE) | ||
156 | ) | ||
157 | { | ||
158 | return 2; | ||
159 | } | ||
160 | else /*Just flat SPP*/ | ||
161 | { | ||
162 | return 1; | ||
163 | } | ||
164 | #else | ||
165 | /* there is no way of knowing what kind of port we have | ||
166 | default to the highest mode possible */ | ||
167 | return 5; | ||
168 | #endif | ||
169 | } | ||
170 | |||
171 | static int bpck6_probe_unit ( PIA *pi ) | ||
172 | { | ||
173 | int out; | ||
174 | |||
175 | if(verbose) | ||
176 | { | ||
177 | printk(KERN_DEBUG "PROBE UNIT %x on port:%x\n",pi->unit,pi->port); | ||
178 | } | ||
179 | |||
180 | /*SET PPC UNIT NUMBER*/ | ||
181 | PPCSTRUCT(pi)->ppc_id=pi->unit; | ||
182 | |||
183 | /*LOWER DOWN TO UNIDIRECTIONAL*/ | ||
184 | PPCSTRUCT(pi)->mode=1; | ||
185 | |||
186 | out=ppc6_open(PPCSTRUCT(pi)); | ||
187 | |||
188 | if(verbose) | ||
189 | { | ||
190 | printk(KERN_DEBUG "ppc_open returned %2x\n",out); | ||
191 | } | ||
192 | |||
193 | if(out) | ||
194 | { | ||
195 | ppc6_close(PPCSTRUCT(pi)); | ||
196 | if(verbose) | ||
197 | { | ||
198 | printk(KERN_DEBUG "leaving probe\n"); | ||
199 | } | ||
200 | return(1); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | if(verbose) | ||
205 | { | ||
206 | printk(KERN_DEBUG "Failed open\n"); | ||
207 | } | ||
208 | return(0); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | static void bpck6_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
213 | { | ||
214 | char *mode_string[5]= | ||
215 | {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"}; | ||
216 | |||
217 | printk("%s: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n",pi->device); | ||
218 | printk("%s: Copyright 2001 by Micro Solutions, Inc., DeKalb IL.\n",pi->device); | ||
219 | printk("%s: BACKPACK %s, Micro Solutions BACKPACK Drive at 0x%x\n", | ||
220 | pi->device,BACKPACK_VERSION,pi->port); | ||
221 | printk("%s: Unit: %d Mode:%d (%s) Delay %d\n",pi->device, | ||
222 | pi->unit,pi->mode,mode_string[pi->mode],pi->delay); | ||
223 | } | ||
224 | |||
225 | static int bpck6_init_proto(PIA *pi) | ||
226 | { | ||
227 | Interface *p = kmalloc(sizeof(Interface), GFP_KERNEL); | ||
228 | |||
229 | if (p) { | ||
230 | memset(p, 0, sizeof(Interface)); | ||
231 | pi->private = (unsigned long)p; | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n", pi->device); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | static void bpck6_release_proto(PIA *pi) | ||
240 | { | ||
241 | kfree((void *)(pi->private)); | ||
242 | } | ||
243 | |||
244 | static struct pi_protocol bpck6 = { | ||
245 | .owner = THIS_MODULE, | ||
246 | .name = "bpck6", | ||
247 | .max_mode = 5, | ||
248 | .epp_first = 2, /* 2-5 use epp (need 8 ports) */ | ||
249 | .max_units = 255, | ||
250 | .write_regr = bpck6_write_regr, | ||
251 | .read_regr = bpck6_read_regr, | ||
252 | .write_block = bpck6_write_block, | ||
253 | .read_block = bpck6_read_block, | ||
254 | .connect = bpck6_connect, | ||
255 | .disconnect = bpck6_disconnect, | ||
256 | .test_port = bpck6_test_port, | ||
257 | .probe_unit = bpck6_probe_unit, | ||
258 | .log_adapter = bpck6_log_adapter, | ||
259 | .init_proto = bpck6_init_proto, | ||
260 | .release_proto = bpck6_release_proto, | ||
261 | }; | ||
262 | |||
263 | static int __init bpck6_init(void) | ||
264 | { | ||
265 | printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n"); | ||
266 | printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n"); | ||
267 | if(verbose) | ||
268 | printk(KERN_DEBUG "bpck6: verbose debug enabled.\n"); | ||
269 | return pi_register(&bpck6) - 1; | ||
270 | } | ||
271 | |||
272 | static void __exit bpck6_exit(void) | ||
273 | { | ||
274 | pi_unregister(&bpck6); | ||
275 | } | ||
276 | |||
277 | MODULE_LICENSE("GPL"); | ||
278 | MODULE_AUTHOR("Micro Solutions Inc."); | ||
279 | MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE"); | ||
280 | module_param(verbose, bool, 0644); | ||
281 | module_init(bpck6_init) | ||
282 | module_exit(bpck6_exit) | ||
diff --git a/drivers/block/paride/comm.c b/drivers/block/paride/comm.c new file mode 100644 index 000000000000..d842956edf76 --- /dev/null +++ b/drivers/block/paride/comm.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | comm.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | comm.c is a low-level protocol driver for some older models | ||
6 | of the DataStor "Commuter" parallel to IDE adapter. Some of | ||
7 | the parallel port devices marketed by Arista currently | ||
8 | use this adapter. | ||
9 | */ | ||
10 | |||
11 | /* Changes: | ||
12 | |||
13 | 1.01 GRG 1998.05.05 init_proto, release_proto | ||
14 | |||
15 | */ | ||
16 | |||
17 | #define COMM_VERSION "1.01" | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/wait.h> | ||
25 | #include <asm/io.h> | ||
26 | |||
27 | #include "paride.h" | ||
28 | |||
29 | /* mode codes: 0 nybble reads, 8-bit writes | ||
30 | 1 8-bit reads and writes | ||
31 | 2 8-bit EPP mode | ||
32 | */ | ||
33 | |||
34 | #define j44(a,b) (((a>>3)&0x0f)|((b<<1)&0xf0)) | ||
35 | |||
36 | #define P1 w2(5);w2(0xd);w2(0xd);w2(5);w2(4); | ||
37 | #define P2 w2(5);w2(7);w2(7);w2(5);w2(4); | ||
38 | |||
39 | /* cont = 0 - access the IDE register file | ||
40 | cont = 1 - access the IDE command set | ||
41 | */ | ||
42 | |||
43 | static int cont_map[2] = { 0x08, 0x10 }; | ||
44 | |||
45 | static int comm_read_regr( PIA *pi, int cont, int regr ) | ||
46 | |||
47 | { int l, h, r; | ||
48 | |||
49 | r = regr + cont_map[cont]; | ||
50 | |||
51 | switch (pi->mode) { | ||
52 | |||
53 | case 0: w0(r); P1; w0(0); | ||
54 | w2(6); l = r1(); w0(0x80); h = r1(); w2(4); | ||
55 | return j44(l,h); | ||
56 | |||
57 | case 1: w0(r+0x20); P1; | ||
58 | w0(0); w2(0x26); h = r0(); w2(4); | ||
59 | return h; | ||
60 | |||
61 | case 2: | ||
62 | case 3: | ||
63 | case 4: w3(r+0x20); r1(); | ||
64 | w2(0x24); h = r4(); w2(4); | ||
65 | return h; | ||
66 | |||
67 | } | ||
68 | return -1; | ||
69 | } | ||
70 | |||
71 | static void comm_write_regr( PIA *pi, int cont, int regr, int val ) | ||
72 | |||
73 | { int r; | ||
74 | |||
75 | r = regr + cont_map[cont]; | ||
76 | |||
77 | switch (pi->mode) { | ||
78 | |||
79 | case 0: | ||
80 | case 1: w0(r); P1; w0(val); P2; | ||
81 | break; | ||
82 | |||
83 | case 2: | ||
84 | case 3: | ||
85 | case 4: w3(r); r1(); w4(val); | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static void comm_connect ( PIA *pi ) | ||
91 | |||
92 | { pi->saved_r0 = r0(); | ||
93 | pi->saved_r2 = r2(); | ||
94 | w2(4); w0(0xff); w2(6); | ||
95 | w2(4); w0(0xaa); w2(6); | ||
96 | w2(4); w0(0x00); w2(6); | ||
97 | w2(4); w0(0x87); w2(6); | ||
98 | w2(4); w0(0xe0); w2(0xc); w2(0xc); w2(4); | ||
99 | } | ||
100 | |||
101 | static void comm_disconnect ( PIA *pi ) | ||
102 | |||
103 | { w2(0); w2(0); w2(0); w2(4); | ||
104 | w0(pi->saved_r0); | ||
105 | w2(pi->saved_r2); | ||
106 | } | ||
107 | |||
108 | static void comm_read_block( PIA *pi, char * buf, int count ) | ||
109 | |||
110 | { int i, l, h; | ||
111 | |||
112 | switch (pi->mode) { | ||
113 | |||
114 | case 0: w0(0x48); P1; | ||
115 | for(i=0;i<count;i++) { | ||
116 | w0(0); w2(6); l = r1(); | ||
117 | w0(0x80); h = r1(); w2(4); | ||
118 | buf[i] = j44(l,h); | ||
119 | } | ||
120 | break; | ||
121 | |||
122 | case 1: w0(0x68); P1; w0(0); | ||
123 | for(i=0;i<count;i++) { | ||
124 | w2(0x26); buf[i] = r0(); w2(0x24); | ||
125 | } | ||
126 | w2(4); | ||
127 | break; | ||
128 | |||
129 | case 2: w3(0x68); r1(); w2(0x24); | ||
130 | for (i=0;i<count;i++) buf[i] = r4(); | ||
131 | w2(4); | ||
132 | break; | ||
133 | |||
134 | case 3: w3(0x68); r1(); w2(0x24); | ||
135 | for (i=0;i<count/2;i++) ((u16 *)buf)[i] = r4w(); | ||
136 | w2(4); | ||
137 | break; | ||
138 | |||
139 | case 4: w3(0x68); r1(); w2(0x24); | ||
140 | for (i=0;i<count/4;i++) ((u32 *)buf)[i] = r4l(); | ||
141 | w2(4); | ||
142 | break; | ||
143 | |||
144 | } | ||
145 | } | ||
146 | |||
147 | /* NB: Watch out for the byte swapped writes ! */ | ||
148 | |||
149 | static void comm_write_block( PIA *pi, char * buf, int count ) | ||
150 | |||
151 | { int k; | ||
152 | |||
153 | switch (pi->mode) { | ||
154 | |||
155 | case 0: | ||
156 | case 1: w0(0x68); P1; | ||
157 | for (k=0;k<count;k++) { | ||
158 | w2(5); w0(buf[k^1]); w2(7); | ||
159 | } | ||
160 | w2(5); w2(4); | ||
161 | break; | ||
162 | |||
163 | case 2: w3(0x48); r1(); | ||
164 | for (k=0;k<count;k++) w4(buf[k^1]); | ||
165 | break; | ||
166 | |||
167 | case 3: w3(0x48); r1(); | ||
168 | for (k=0;k<count/2;k++) w4w(pi_swab16(buf,k)); | ||
169 | break; | ||
170 | |||
171 | case 4: w3(0x48); r1(); | ||
172 | for (k=0;k<count/4;k++) w4l(pi_swab32(buf,k)); | ||
173 | break; | ||
174 | |||
175 | |||
176 | } | ||
177 | } | ||
178 | |||
179 | static void comm_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
180 | |||
181 | { char *mode_string[5] = {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"}; | ||
182 | |||
183 | printk("%s: comm %s, DataStor Commuter at 0x%x, ", | ||
184 | pi->device,COMM_VERSION,pi->port); | ||
185 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
186 | mode_string[pi->mode],pi->delay); | ||
187 | |||
188 | } | ||
189 | |||
190 | static struct pi_protocol comm = { | ||
191 | .owner = THIS_MODULE, | ||
192 | .name = "comm", | ||
193 | .max_mode = 5, | ||
194 | .epp_first = 2, | ||
195 | .default_delay = 1, | ||
196 | .max_units = 1, | ||
197 | .write_regr = comm_write_regr, | ||
198 | .read_regr = comm_read_regr, | ||
199 | .write_block = comm_write_block, | ||
200 | .read_block = comm_read_block, | ||
201 | .connect = comm_connect, | ||
202 | .disconnect = comm_disconnect, | ||
203 | .log_adapter = comm_log_adapter, | ||
204 | }; | ||
205 | |||
206 | static int __init comm_init(void) | ||
207 | { | ||
208 | return pi_register(&comm)-1; | ||
209 | } | ||
210 | |||
211 | static void __exit comm_exit(void) | ||
212 | { | ||
213 | pi_unregister(&comm); | ||
214 | } | ||
215 | |||
216 | MODULE_LICENSE("GPL"); | ||
217 | module_init(comm_init) | ||
218 | module_exit(comm_exit) | ||
diff --git a/drivers/block/paride/dstr.c b/drivers/block/paride/dstr.c new file mode 100644 index 000000000000..04d53bf58e8c --- /dev/null +++ b/drivers/block/paride/dstr.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | dstr.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | dstr.c is a low-level protocol driver for the | ||
6 | DataStor EP2000 parallel to IDE adapter chip. | ||
7 | |||
8 | */ | ||
9 | |||
10 | /* Changes: | ||
11 | |||
12 | 1.01 GRG 1998.05.06 init_proto, release_proto | ||
13 | |||
14 | */ | ||
15 | |||
16 | #define DSTR_VERSION "1.01" | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | #include "paride.h" | ||
27 | |||
28 | /* mode codes: 0 nybble reads, 8-bit writes | ||
29 | 1 8-bit reads and writes | ||
30 | 2 8-bit EPP mode | ||
31 | 3 EPP-16 | ||
32 | 4 EPP-32 | ||
33 | */ | ||
34 | |||
35 | #define j44(a,b) (((a>>3)&0x07)|((~a>>4)&0x08)|((b<<1)&0x70)|((~b)&0x80)) | ||
36 | |||
37 | #define P1 w2(5);w2(0xd);w2(5);w2(4); | ||
38 | #define P2 w2(5);w2(7);w2(5);w2(4); | ||
39 | #define P3 w2(6);w2(4);w2(6);w2(4); | ||
40 | |||
41 | /* cont = 0 - access the IDE register file | ||
42 | cont = 1 - access the IDE command set | ||
43 | */ | ||
44 | |||
45 | static int cont_map[2] = { 0x20, 0x40 }; | ||
46 | |||
47 | static int dstr_read_regr( PIA *pi, int cont, int regr ) | ||
48 | |||
49 | { int a, b, r; | ||
50 | |||
51 | r = regr + cont_map[cont]; | ||
52 | |||
53 | w0(0x81); P1; | ||
54 | if (pi->mode) { w0(0x11); } else { w0(1); } | ||
55 | P2; w0(r); P1; | ||
56 | |||
57 | switch (pi->mode) { | ||
58 | |||
59 | case 0: w2(6); a = r1(); w2(4); w2(6); b = r1(); w2(4); | ||
60 | return j44(a,b); | ||
61 | |||
62 | case 1: w0(0); w2(0x26); a = r0(); w2(4); | ||
63 | return a; | ||
64 | |||
65 | case 2: | ||
66 | case 3: | ||
67 | case 4: w2(0x24); a = r4(); w2(4); | ||
68 | return a; | ||
69 | |||
70 | } | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | static void dstr_write_regr( PIA *pi, int cont, int regr, int val ) | ||
75 | |||
76 | { int r; | ||
77 | |||
78 | r = regr + cont_map[cont]; | ||
79 | |||
80 | w0(0x81); P1; | ||
81 | if (pi->mode >= 2) { w0(0x11); } else { w0(1); } | ||
82 | P2; w0(r); P1; | ||
83 | |||
84 | switch (pi->mode) { | ||
85 | |||
86 | case 0: | ||
87 | case 1: w0(val); w2(5); w2(7); w2(5); w2(4); | ||
88 | break; | ||
89 | |||
90 | case 2: | ||
91 | case 3: | ||
92 | case 4: w4(val); | ||
93 | break; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | #define CCP(x) w0(0xff);w2(0xc);w2(4);\ | ||
98 | w0(0xaa);w0(0x55);w0(0);w0(0xff);w0(0x87);w0(0x78);\ | ||
99 | w0(x);w2(5);w2(4); | ||
100 | |||
101 | static void dstr_connect ( PIA *pi ) | ||
102 | |||
103 | { pi->saved_r0 = r0(); | ||
104 | pi->saved_r2 = r2(); | ||
105 | w2(4); CCP(0xe0); w0(0xff); | ||
106 | } | ||
107 | |||
108 | static void dstr_disconnect ( PIA *pi ) | ||
109 | |||
110 | { CCP(0x30); | ||
111 | w0(pi->saved_r0); | ||
112 | w2(pi->saved_r2); | ||
113 | } | ||
114 | |||
115 | static void dstr_read_block( PIA *pi, char * buf, int count ) | ||
116 | |||
117 | { int k, a, b; | ||
118 | |||
119 | w0(0x81); P1; | ||
120 | if (pi->mode) { w0(0x19); } else { w0(9); } | ||
121 | P2; w0(0x82); P1; P3; w0(0x20); P1; | ||
122 | |||
123 | switch (pi->mode) { | ||
124 | |||
125 | case 0: for (k=0;k<count;k++) { | ||
126 | w2(6); a = r1(); w2(4); | ||
127 | w2(6); b = r1(); w2(4); | ||
128 | buf[k] = j44(a,b); | ||
129 | } | ||
130 | break; | ||
131 | |||
132 | case 1: w0(0); | ||
133 | for (k=0;k<count;k++) { | ||
134 | w2(0x26); buf[k] = r0(); w2(0x24); | ||
135 | } | ||
136 | w2(4); | ||
137 | break; | ||
138 | |||
139 | case 2: w2(0x24); | ||
140 | for (k=0;k<count;k++) buf[k] = r4(); | ||
141 | w2(4); | ||
142 | break; | ||
143 | |||
144 | case 3: w2(0x24); | ||
145 | for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w(); | ||
146 | w2(4); | ||
147 | break; | ||
148 | |||
149 | case 4: w2(0x24); | ||
150 | for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l(); | ||
151 | w2(4); | ||
152 | break; | ||
153 | |||
154 | } | ||
155 | } | ||
156 | |||
157 | static void dstr_write_block( PIA *pi, char * buf, int count ) | ||
158 | |||
159 | { int k; | ||
160 | |||
161 | w0(0x81); P1; | ||
162 | if (pi->mode) { w0(0x19); } else { w0(9); } | ||
163 | P2; w0(0x82); P1; P3; w0(0x20); P1; | ||
164 | |||
165 | switch (pi->mode) { | ||
166 | |||
167 | case 0: | ||
168 | case 1: for (k=0;k<count;k++) { | ||
169 | w2(5); w0(buf[k]); w2(7); | ||
170 | } | ||
171 | w2(5); w2(4); | ||
172 | break; | ||
173 | |||
174 | case 2: w2(0xc5); | ||
175 | for (k=0;k<count;k++) w4(buf[k]); | ||
176 | w2(0xc4); | ||
177 | break; | ||
178 | |||
179 | case 3: w2(0xc5); | ||
180 | for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); | ||
181 | w2(0xc4); | ||
182 | break; | ||
183 | |||
184 | case 4: w2(0xc5); | ||
185 | for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); | ||
186 | w2(0xc4); | ||
187 | break; | ||
188 | |||
189 | } | ||
190 | } | ||
191 | |||
192 | |||
193 | static void dstr_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
194 | |||
195 | { char *mode_string[5] = {"4-bit","8-bit","EPP-8", | ||
196 | "EPP-16","EPP-32"}; | ||
197 | |||
198 | printk("%s: dstr %s, DataStor EP2000 at 0x%x, ", | ||
199 | pi->device,DSTR_VERSION,pi->port); | ||
200 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
201 | mode_string[pi->mode],pi->delay); | ||
202 | |||
203 | } | ||
204 | |||
205 | static struct pi_protocol dstr = { | ||
206 | .owner = THIS_MODULE, | ||
207 | .name = "dstr", | ||
208 | .max_mode = 5, | ||
209 | .epp_first = 2, | ||
210 | .default_delay = 1, | ||
211 | .max_units = 1, | ||
212 | .write_regr = dstr_write_regr, | ||
213 | .read_regr = dstr_read_regr, | ||
214 | .write_block = dstr_write_block, | ||
215 | .read_block = dstr_read_block, | ||
216 | .connect = dstr_connect, | ||
217 | .disconnect = dstr_disconnect, | ||
218 | .log_adapter = dstr_log_adapter, | ||
219 | }; | ||
220 | |||
221 | static int __init dstr_init(void) | ||
222 | { | ||
223 | return pi_register(&dstr)-1; | ||
224 | } | ||
225 | |||
226 | static void __exit dstr_exit(void) | ||
227 | { | ||
228 | pi_unregister(&dstr); | ||
229 | } | ||
230 | |||
231 | MODULE_LICENSE("GPL"); | ||
232 | module_init(dstr_init) | ||
233 | module_exit(dstr_exit) | ||
diff --git a/drivers/block/paride/epat.c b/drivers/block/paride/epat.c new file mode 100644 index 000000000000..55d1c0a1fb90 --- /dev/null +++ b/drivers/block/paride/epat.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | epat.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is the low level protocol driver for the EPAT parallel | ||
6 | to IDE adapter from Shuttle Technologies. This adapter is | ||
7 | used in many popular parallel port disk products such as the | ||
8 | SyQuest EZ drives, the Avatar Shark and the Imation SuperDisk. | ||
9 | |||
10 | */ | ||
11 | |||
12 | /* Changes: | ||
13 | |||
14 | 1.01 GRG 1998.05.06 init_proto, release_proto | ||
15 | 1.02 Joshua b. Jore CPP(renamed), epat_connect, epat_disconnect | ||
16 | |||
17 | */ | ||
18 | |||
19 | #define EPAT_VERSION "1.02" | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/wait.h> | ||
27 | #include <asm/io.h> | ||
28 | |||
29 | #include "paride.h" | ||
30 | |||
31 | #define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) | ||
32 | #define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) | ||
33 | |||
34 | static int epatc8; | ||
35 | |||
36 | module_param(epatc8, int, 0); | ||
37 | MODULE_PARM_DESC(epatc8, "support for the Shuttle EP1284 chip, " | ||
38 | "used in any recent Imation SuperDisk (LS-120) drive."); | ||
39 | |||
40 | /* cont = 0 IDE register file | ||
41 | cont = 1 IDE control registers | ||
42 | cont = 2 internal EPAT registers | ||
43 | */ | ||
44 | |||
45 | static int cont_map[3] = { 0x18, 0x10, 0 }; | ||
46 | |||
47 | static void epat_write_regr( PIA *pi, int cont, int regr, int val) | ||
48 | |||
49 | { int r; | ||
50 | |||
51 | r = regr + cont_map[cont]; | ||
52 | |||
53 | switch (pi->mode) { | ||
54 | |||
55 | case 0: | ||
56 | case 1: | ||
57 | case 2: w0(0x60+r); w2(1); w0(val); w2(4); | ||
58 | break; | ||
59 | |||
60 | case 3: | ||
61 | case 4: | ||
62 | case 5: w3(0x40+r); w4(val); | ||
63 | break; | ||
64 | |||
65 | } | ||
66 | } | ||
67 | |||
68 | static int epat_read_regr( PIA *pi, int cont, int regr ) | ||
69 | |||
70 | { int a, b, r; | ||
71 | |||
72 | r = regr + cont_map[cont]; | ||
73 | |||
74 | switch (pi->mode) { | ||
75 | |||
76 | case 0: w0(r); w2(1); w2(3); | ||
77 | a = r1(); w2(4); b = r1(); | ||
78 | return j44(a,b); | ||
79 | |||
80 | case 1: w0(0x40+r); w2(1); w2(4); | ||
81 | a = r1(); b = r2(); w0(0xff); | ||
82 | return j53(a,b); | ||
83 | |||
84 | case 2: w0(0x20+r); w2(1); w2(0x25); | ||
85 | a = r0(); w2(4); | ||
86 | return a; | ||
87 | |||
88 | case 3: | ||
89 | case 4: | ||
90 | case 5: w3(r); w2(0x24); a = r4(); w2(4); | ||
91 | return a; | ||
92 | |||
93 | } | ||
94 | return -1; /* never gets here */ | ||
95 | } | ||
96 | |||
97 | static void epat_read_block( PIA *pi, char * buf, int count ) | ||
98 | |||
99 | { int k, ph, a, b; | ||
100 | |||
101 | switch (pi->mode) { | ||
102 | |||
103 | case 0: w0(7); w2(1); w2(3); w0(0xff); | ||
104 | ph = 0; | ||
105 | for(k=0;k<count;k++) { | ||
106 | if (k == count-1) w0(0xfd); | ||
107 | w2(6+ph); a = r1(); | ||
108 | if (a & 8) b = a; | ||
109 | else { w2(4+ph); b = r1(); } | ||
110 | buf[k] = j44(a,b); | ||
111 | ph = 1 - ph; | ||
112 | } | ||
113 | w0(0); w2(4); | ||
114 | break; | ||
115 | |||
116 | case 1: w0(0x47); w2(1); w2(5); w0(0xff); | ||
117 | ph = 0; | ||
118 | for(k=0;k<count;k++) { | ||
119 | if (k == count-1) w0(0xfd); | ||
120 | w2(4+ph); | ||
121 | a = r1(); b = r2(); | ||
122 | buf[k] = j53(a,b); | ||
123 | ph = 1 - ph; | ||
124 | } | ||
125 | w0(0); w2(4); | ||
126 | break; | ||
127 | |||
128 | case 2: w0(0x27); w2(1); w2(0x25); w0(0); | ||
129 | ph = 0; | ||
130 | for(k=0;k<count-1;k++) { | ||
131 | w2(0x24+ph); | ||
132 | buf[k] = r0(); | ||
133 | ph = 1 - ph; | ||
134 | } | ||
135 | w2(0x26); w2(0x27); buf[count-1] = r0(); | ||
136 | w2(0x25); w2(4); | ||
137 | break; | ||
138 | |||
139 | case 3: w3(0x80); w2(0x24); | ||
140 | for(k=0;k<count-1;k++) buf[k] = r4(); | ||
141 | w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4(); | ||
142 | w2(4); | ||
143 | break; | ||
144 | |||
145 | case 4: w3(0x80); w2(0x24); | ||
146 | for(k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w(); | ||
147 | buf[count-2] = r4(); | ||
148 | w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4(); | ||
149 | w2(4); | ||
150 | break; | ||
151 | |||
152 | case 5: w3(0x80); w2(0x24); | ||
153 | for(k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l(); | ||
154 | for(k=count-4;k<count-1;k++) buf[k] = r4(); | ||
155 | w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4(); | ||
156 | w2(4); | ||
157 | break; | ||
158 | |||
159 | } | ||
160 | } | ||
161 | |||
162 | static void epat_write_block( PIA *pi, char * buf, int count ) | ||
163 | |||
164 | { int ph, k; | ||
165 | |||
166 | switch (pi->mode) { | ||
167 | |||
168 | case 0: | ||
169 | case 1: | ||
170 | case 2: w0(0x67); w2(1); w2(5); | ||
171 | ph = 0; | ||
172 | for(k=0;k<count;k++) { | ||
173 | w0(buf[k]); | ||
174 | w2(4+ph); | ||
175 | ph = 1 - ph; | ||
176 | } | ||
177 | w2(7); w2(4); | ||
178 | break; | ||
179 | |||
180 | case 3: w3(0xc0); | ||
181 | for(k=0;k<count;k++) w4(buf[k]); | ||
182 | w2(4); | ||
183 | break; | ||
184 | |||
185 | case 4: w3(0xc0); | ||
186 | for(k=0;k<(count/2);k++) w4w(((u16 *)buf)[k]); | ||
187 | w2(4); | ||
188 | break; | ||
189 | |||
190 | case 5: w3(0xc0); | ||
191 | for(k=0;k<(count/4);k++) w4l(((u32 *)buf)[k]); | ||
192 | w2(4); | ||
193 | break; | ||
194 | |||
195 | } | ||
196 | } | ||
197 | |||
198 | /* these macros access the EPAT registers in native addressing */ | ||
199 | |||
200 | #define WR(r,v) epat_write_regr(pi,2,r,v) | ||
201 | #define RR(r) (epat_read_regr(pi,2,r)) | ||
202 | |||
203 | /* and these access the IDE task file */ | ||
204 | |||
205 | #define WRi(r,v) epat_write_regr(pi,0,r,v) | ||
206 | #define RRi(r) (epat_read_regr(pi,0,r)) | ||
207 | |||
208 | /* FIXME: the CPP stuff should be fixed to handle multiple EPATs on a chain */ | ||
209 | |||
210 | #define CPP(x) w2(4);w0(0x22);w0(0xaa);w0(0x55);w0(0);w0(0xff);\ | ||
211 | w0(0x87);w0(0x78);w0(x);w2(4);w2(5);w2(4);w0(0xff); | ||
212 | |||
213 | static void epat_connect ( PIA *pi ) | ||
214 | |||
215 | { pi->saved_r0 = r0(); | ||
216 | pi->saved_r2 = r2(); | ||
217 | |||
218 | /* Initialize the chip */ | ||
219 | CPP(0); | ||
220 | |||
221 | if (epatc8) { | ||
222 | CPP(0x40);CPP(0xe0); | ||
223 | w0(0);w2(1);w2(4); | ||
224 | WR(0x8,0x12);WR(0xc,0x14);WR(0x12,0x10); | ||
225 | WR(0xe,0xf);WR(0xf,4); | ||
226 | /* WR(0xe,0xa);WR(0xf,4); */ | ||
227 | WR(0xe,0xd);WR(0xf,0); | ||
228 | /* CPP(0x30); */ | ||
229 | } | ||
230 | |||
231 | /* Connect to the chip */ | ||
232 | CPP(0xe0); | ||
233 | w0(0);w2(1);w2(4); /* Idle into SPP */ | ||
234 | if (pi->mode >= 3) { | ||
235 | w0(0);w2(1);w2(4);w2(0xc); | ||
236 | /* Request EPP */ | ||
237 | w0(0x40);w2(6);w2(7);w2(4);w2(0xc);w2(4); | ||
238 | } | ||
239 | |||
240 | if (!epatc8) { | ||
241 | WR(8,0x10); WR(0xc,0x14); WR(0xa,0x38); WR(0x12,0x10); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | static void epat_disconnect (PIA *pi) | ||
246 | { CPP(0x30); | ||
247 | w0(pi->saved_r0); | ||
248 | w2(pi->saved_r2); | ||
249 | } | ||
250 | |||
251 | static int epat_test_proto( PIA *pi, char * scratch, int verbose ) | ||
252 | |||
253 | { int k, j, f, cc; | ||
254 | int e[2] = {0,0}; | ||
255 | |||
256 | epat_connect(pi); | ||
257 | cc = RR(0xd); | ||
258 | epat_disconnect(pi); | ||
259 | |||
260 | epat_connect(pi); | ||
261 | for (j=0;j<2;j++) { | ||
262 | WRi(6,0xa0+j*0x10); | ||
263 | for (k=0;k<256;k++) { | ||
264 | WRi(2,k^0xaa); | ||
265 | WRi(3,k^0x55); | ||
266 | if (RRi(2) != (k^0xaa)) e[j]++; | ||
267 | } | ||
268 | } | ||
269 | epat_disconnect(pi); | ||
270 | |||
271 | f = 0; | ||
272 | epat_connect(pi); | ||
273 | WR(0x13,1); WR(0x13,0); WR(0xa,0x11); | ||
274 | epat_read_block(pi,scratch,512); | ||
275 | |||
276 | for (k=0;k<256;k++) { | ||
277 | if ((scratch[2*k] & 0xff) != k) f++; | ||
278 | if ((scratch[2*k+1] & 0xff) != (0xff-k)) f++; | ||
279 | } | ||
280 | epat_disconnect(pi); | ||
281 | |||
282 | if (verbose) { | ||
283 | printk("%s: epat: port 0x%x, mode %d, ccr %x, test=(%d,%d,%d)\n", | ||
284 | pi->device,pi->port,pi->mode,cc,e[0],e[1],f); | ||
285 | } | ||
286 | |||
287 | return (e[0] && e[1]) || f; | ||
288 | } | ||
289 | |||
290 | static void epat_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
291 | |||
292 | { int ver; | ||
293 | char *mode_string[6] = | ||
294 | {"4-bit","5/3","8-bit","EPP-8","EPP-16","EPP-32"}; | ||
295 | |||
296 | epat_connect(pi); | ||
297 | WR(0xa,0x38); /* read the version code */ | ||
298 | ver = RR(0xb); | ||
299 | epat_disconnect(pi); | ||
300 | |||
301 | printk("%s: epat %s, Shuttle EPAT chip %x at 0x%x, ", | ||
302 | pi->device,EPAT_VERSION,ver,pi->port); | ||
303 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
304 | mode_string[pi->mode],pi->delay); | ||
305 | |||
306 | } | ||
307 | |||
308 | static struct pi_protocol epat = { | ||
309 | .owner = THIS_MODULE, | ||
310 | .name = "epat", | ||
311 | .max_mode = 6, | ||
312 | .epp_first = 3, | ||
313 | .default_delay = 1, | ||
314 | .max_units = 1, | ||
315 | .write_regr = epat_write_regr, | ||
316 | .read_regr = epat_read_regr, | ||
317 | .write_block = epat_write_block, | ||
318 | .read_block = epat_read_block, | ||
319 | .connect = epat_connect, | ||
320 | .disconnect = epat_disconnect, | ||
321 | .test_proto = epat_test_proto, | ||
322 | .log_adapter = epat_log_adapter, | ||
323 | }; | ||
324 | |||
325 | static int __init epat_init(void) | ||
326 | { | ||
327 | #ifdef CONFIG_PARIDE_EPATC8 | ||
328 | epatc8 = 1; | ||
329 | #endif | ||
330 | return pi_register(&epat)-1; | ||
331 | } | ||
332 | |||
333 | static void __exit epat_exit(void) | ||
334 | { | ||
335 | pi_unregister(&epat); | ||
336 | } | ||
337 | |||
338 | MODULE_LICENSE("GPL"); | ||
339 | module_init(epat_init) | ||
340 | module_exit(epat_exit) | ||
diff --git a/drivers/block/paride/epia.c b/drivers/block/paride/epia.c new file mode 100644 index 000000000000..0f2e0c292d82 --- /dev/null +++ b/drivers/block/paride/epia.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | epia.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | epia.c is a low-level protocol driver for Shuttle Technologies | ||
6 | EPIA parallel to IDE adapter chip. This device is now obsolete | ||
7 | and has been replaced with the EPAT chip, which is supported | ||
8 | by epat.c, however, some devices based on EPIA are still | ||
9 | available. | ||
10 | |||
11 | */ | ||
12 | |||
13 | /* Changes: | ||
14 | |||
15 | 1.01 GRG 1998.05.06 init_proto, release_proto | ||
16 | 1.02 GRG 1998.06.17 support older versions of EPIA | ||
17 | |||
18 | */ | ||
19 | |||
20 | #define EPIA_VERSION "1.02" | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <asm/io.h> | ||
29 | |||
30 | #include "paride.h" | ||
31 | |||
32 | /* mode codes: 0 nybble reads on port 1, 8-bit writes | ||
33 | 1 5/3 reads on ports 1 & 2, 8-bit writes | ||
34 | 2 8-bit reads and writes | ||
35 | 3 8-bit EPP mode | ||
36 | 4 16-bit EPP | ||
37 | 5 32-bit EPP | ||
38 | */ | ||
39 | |||
40 | #define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) | ||
41 | #define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) | ||
42 | |||
43 | /* cont = 0 IDE register file | ||
44 | cont = 1 IDE control registers | ||
45 | */ | ||
46 | |||
47 | static int cont_map[2] = { 0, 0x80 }; | ||
48 | |||
49 | static int epia_read_regr( PIA *pi, int cont, int regr ) | ||
50 | |||
51 | { int a, b, r; | ||
52 | |||
53 | regr += cont_map[cont]; | ||
54 | |||
55 | switch (pi->mode) { | ||
56 | |||
57 | case 0: r = regr^0x39; | ||
58 | w0(r); w2(1); w2(3); w0(r); | ||
59 | a = r1(); w2(1); b = r1(); w2(4); | ||
60 | return j44(a,b); | ||
61 | |||
62 | case 1: r = regr^0x31; | ||
63 | w0(r); w2(1); w0(r&0x37); | ||
64 | w2(3); w2(5); w0(r|0xf0); | ||
65 | a = r1(); b = r2(); w2(4); | ||
66 | return j53(a,b); | ||
67 | |||
68 | case 2: r = regr^0x29; | ||
69 | w0(r); w2(1); w2(0X21); w2(0x23); | ||
70 | a = r0(); w2(4); | ||
71 | return a; | ||
72 | |||
73 | case 3: | ||
74 | case 4: | ||
75 | case 5: w3(regr); w2(0x24); a = r4(); w2(4); | ||
76 | return a; | ||
77 | |||
78 | } | ||
79 | return -1; | ||
80 | } | ||
81 | |||
82 | static void epia_write_regr( PIA *pi, int cont, int regr, int val) | ||
83 | |||
84 | { int r; | ||
85 | |||
86 | regr += cont_map[cont]; | ||
87 | |||
88 | switch (pi->mode) { | ||
89 | |||
90 | case 0: | ||
91 | case 1: | ||
92 | case 2: r = regr^0x19; | ||
93 | w0(r); w2(1); w0(val); w2(3); w2(4); | ||
94 | break; | ||
95 | |||
96 | case 3: | ||
97 | case 4: | ||
98 | case 5: r = regr^0x40; | ||
99 | w3(r); w4(val); w2(4); | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | #define WR(r,v) epia_write_regr(pi,0,r,v) | ||
105 | #define RR(r) (epia_read_regr(pi,0,r)) | ||
106 | |||
107 | /* The use of register 0x84 is entirely unclear - it seems to control | ||
108 | some EPP counters ... currently we know about 3 different block | ||
109 | sizes: the standard 512 byte reads and writes, 12 byte writes and | ||
110 | 2048 byte reads (the last two being used in the CDrom drivers. | ||
111 | */ | ||
112 | |||
113 | static void epia_connect ( PIA *pi ) | ||
114 | |||
115 | { pi->saved_r0 = r0(); | ||
116 | pi->saved_r2 = r2(); | ||
117 | |||
118 | w2(4); w0(0xa0); w0(0x50); w0(0xc0); w0(0x30); w0(0xa0); w0(0); | ||
119 | w2(1); w2(4); | ||
120 | if (pi->mode >= 3) { | ||
121 | w0(0xa); w2(1); w2(4); w0(0x82); w2(4); w2(0xc); w2(4); | ||
122 | w2(0x24); w2(0x26); w2(4); | ||
123 | } | ||
124 | WR(0x86,8); | ||
125 | } | ||
126 | |||
127 | static void epia_disconnect ( PIA *pi ) | ||
128 | |||
129 | { /* WR(0x84,0x10); */ | ||
130 | w0(pi->saved_r0); | ||
131 | w2(1); w2(4); | ||
132 | w0(pi->saved_r0); | ||
133 | w2(pi->saved_r2); | ||
134 | } | ||
135 | |||
136 | static void epia_read_block( PIA *pi, char * buf, int count ) | ||
137 | |||
138 | { int k, ph, a, b; | ||
139 | |||
140 | switch (pi->mode) { | ||
141 | |||
142 | case 0: w0(0x81); w2(1); w2(3); w0(0xc1); | ||
143 | ph = 1; | ||
144 | for (k=0;k<count;k++) { | ||
145 | w2(2+ph); a = r1(); | ||
146 | w2(4+ph); b = r1(); | ||
147 | buf[k] = j44(a,b); | ||
148 | ph = 1 - ph; | ||
149 | } | ||
150 | w0(0); w2(4); | ||
151 | break; | ||
152 | |||
153 | case 1: w0(0x91); w2(1); w0(0x10); w2(3); | ||
154 | w0(0x51); w2(5); w0(0xd1); | ||
155 | ph = 1; | ||
156 | for (k=0;k<count;k++) { | ||
157 | w2(4+ph); | ||
158 | a = r1(); b = r2(); | ||
159 | buf[k] = j53(a,b); | ||
160 | ph = 1 - ph; | ||
161 | } | ||
162 | w0(0); w2(4); | ||
163 | break; | ||
164 | |||
165 | case 2: w0(0x89); w2(1); w2(0x23); w2(0x21); | ||
166 | ph = 1; | ||
167 | for (k=0;k<count;k++) { | ||
168 | w2(0x24+ph); | ||
169 | buf[k] = r0(); | ||
170 | ph = 1 - ph; | ||
171 | } | ||
172 | w2(6); w2(4); | ||
173 | break; | ||
174 | |||
175 | case 3: if (count > 512) WR(0x84,3); | ||
176 | w3(0); w2(0x24); | ||
177 | for (k=0;k<count;k++) buf[k] = r4(); | ||
178 | w2(4); WR(0x84,0); | ||
179 | break; | ||
180 | |||
181 | case 4: if (count > 512) WR(0x84,3); | ||
182 | w3(0); w2(0x24); | ||
183 | for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w(); | ||
184 | w2(4); WR(0x84,0); | ||
185 | break; | ||
186 | |||
187 | case 5: if (count > 512) WR(0x84,3); | ||
188 | w3(0); w2(0x24); | ||
189 | for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l(); | ||
190 | w2(4); WR(0x84,0); | ||
191 | break; | ||
192 | |||
193 | } | ||
194 | } | ||
195 | |||
196 | static void epia_write_block( PIA *pi, char * buf, int count ) | ||
197 | |||
198 | { int ph, k, last, d; | ||
199 | |||
200 | switch (pi->mode) { | ||
201 | |||
202 | case 0: | ||
203 | case 1: | ||
204 | case 2: w0(0xa1); w2(1); w2(3); w2(1); w2(5); | ||
205 | ph = 0; last = 0x8000; | ||
206 | for (k=0;k<count;k++) { | ||
207 | d = buf[k]; | ||
208 | if (d != last) { last = d; w0(d); } | ||
209 | w2(4+ph); | ||
210 | ph = 1 - ph; | ||
211 | } | ||
212 | w2(7); w2(4); | ||
213 | break; | ||
214 | |||
215 | case 3: if (count < 512) WR(0x84,1); | ||
216 | w3(0x40); | ||
217 | for (k=0;k<count;k++) w4(buf[k]); | ||
218 | if (count < 512) WR(0x84,0); | ||
219 | break; | ||
220 | |||
221 | case 4: if (count < 512) WR(0x84,1); | ||
222 | w3(0x40); | ||
223 | for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); | ||
224 | if (count < 512) WR(0x84,0); | ||
225 | break; | ||
226 | |||
227 | case 5: if (count < 512) WR(0x84,1); | ||
228 | w3(0x40); | ||
229 | for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); | ||
230 | if (count < 512) WR(0x84,0); | ||
231 | break; | ||
232 | |||
233 | } | ||
234 | |||
235 | } | ||
236 | |||
237 | static int epia_test_proto( PIA *pi, char * scratch, int verbose ) | ||
238 | |||
239 | { int j, k, f; | ||
240 | int e[2] = {0,0}; | ||
241 | |||
242 | epia_connect(pi); | ||
243 | for (j=0;j<2;j++) { | ||
244 | WR(6,0xa0+j*0x10); | ||
245 | for (k=0;k<256;k++) { | ||
246 | WR(2,k^0xaa); | ||
247 | WR(3,k^0x55); | ||
248 | if (RR(2) != (k^0xaa)) e[j]++; | ||
249 | } | ||
250 | WR(2,1); WR(3,1); | ||
251 | } | ||
252 | epia_disconnect(pi); | ||
253 | |||
254 | f = 0; | ||
255 | epia_connect(pi); | ||
256 | WR(0x84,8); | ||
257 | epia_read_block(pi,scratch,512); | ||
258 | for (k=0;k<256;k++) { | ||
259 | if ((scratch[2*k] & 0xff) != ((k+1) & 0xff)) f++; | ||
260 | if ((scratch[2*k+1] & 0xff) != ((-2-k) & 0xff)) f++; | ||
261 | } | ||
262 | WR(0x84,0); | ||
263 | epia_disconnect(pi); | ||
264 | |||
265 | if (verbose) { | ||
266 | printk("%s: epia: port 0x%x, mode %d, test=(%d,%d,%d)\n", | ||
267 | pi->device,pi->port,pi->mode,e[0],e[1],f); | ||
268 | } | ||
269 | |||
270 | return (e[0] && e[1]) || f; | ||
271 | |||
272 | } | ||
273 | |||
274 | |||
275 | static void epia_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
276 | |||
277 | { char *mode_string[6] = {"4-bit","5/3","8-bit", | ||
278 | "EPP-8","EPP-16","EPP-32"}; | ||
279 | |||
280 | printk("%s: epia %s, Shuttle EPIA at 0x%x, ", | ||
281 | pi->device,EPIA_VERSION,pi->port); | ||
282 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
283 | mode_string[pi->mode],pi->delay); | ||
284 | |||
285 | } | ||
286 | |||
287 | static struct pi_protocol epia = { | ||
288 | .owner = THIS_MODULE, | ||
289 | .name = "epia", | ||
290 | .max_mode = 6, | ||
291 | .epp_first = 3, | ||
292 | .default_delay = 1, | ||
293 | .max_units = 1, | ||
294 | .write_regr = epia_write_regr, | ||
295 | .read_regr = epia_read_regr, | ||
296 | .write_block = epia_write_block, | ||
297 | .read_block = epia_read_block, | ||
298 | .connect = epia_connect, | ||
299 | .disconnect = epia_disconnect, | ||
300 | .test_proto = epia_test_proto, | ||
301 | .log_adapter = epia_log_adapter, | ||
302 | }; | ||
303 | |||
304 | static int __init epia_init(void) | ||
305 | { | ||
306 | return pi_register(&epia)-1; | ||
307 | } | ||
308 | |||
309 | static void __exit epia_exit(void) | ||
310 | { | ||
311 | pi_unregister(&epia); | ||
312 | } | ||
313 | |||
314 | MODULE_LICENSE("GPL"); | ||
315 | module_init(epia_init) | ||
316 | module_exit(epia_exit) | ||
diff --git a/drivers/block/paride/fit2.c b/drivers/block/paride/fit2.c new file mode 100644 index 000000000000..e0f0691d8bc2 --- /dev/null +++ b/drivers/block/paride/fit2.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | fit2.c (c) 1998 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | fit2.c is a low-level protocol driver for the older version | ||
6 | of the Fidelity International Technology parallel port adapter. | ||
7 | This adapter is used in their TransDisk 2000 and older TransDisk | ||
8 | 3000 portable hard-drives. As far as I can tell, this device | ||
9 | supports 4-bit mode _only_. | ||
10 | |||
11 | Newer models of the FIT products use an enhanced protocol. | ||
12 | The "fit3" protocol module should support current drives. | ||
13 | |||
14 | */ | ||
15 | |||
16 | #define FIT2_VERSION "1.0" | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | #include "paride.h" | ||
27 | |||
28 | #define j44(a,b) (((a>>4)&0x0f)|(b&0xf0)) | ||
29 | |||
30 | /* cont = 0 - access the IDE register file | ||
31 | cont = 1 - access the IDE command set | ||
32 | |||
33 | NB: The FIT adapter does not appear to use the control registers. | ||
34 | So, we map ALT_STATUS to STATUS and NO-OP writes to the device | ||
35 | control register - this means that IDE reset will not work on these | ||
36 | devices. | ||
37 | |||
38 | */ | ||
39 | |||
40 | static void fit2_write_regr( PIA *pi, int cont, int regr, int val) | ||
41 | |||
42 | { if (cont == 1) return; | ||
43 | w2(0xc); w0(regr); w2(4); w0(val); w2(5); w0(0); w2(4); | ||
44 | } | ||
45 | |||
46 | static int fit2_read_regr( PIA *pi, int cont, int regr ) | ||
47 | |||
48 | { int a, b, r; | ||
49 | |||
50 | if (cont) { | ||
51 | if (regr != 6) return 0xff; | ||
52 | r = 7; | ||
53 | } else r = regr + 0x10; | ||
54 | |||
55 | w2(0xc); w0(r); w2(4); w2(5); | ||
56 | w0(0); a = r1(); | ||
57 | w0(1); b = r1(); | ||
58 | w2(4); | ||
59 | |||
60 | return j44(a,b); | ||
61 | |||
62 | } | ||
63 | |||
64 | static void fit2_read_block( PIA *pi, char * buf, int count ) | ||
65 | |||
66 | { int k, a, b, c, d; | ||
67 | |||
68 | w2(0xc); w0(0x10); | ||
69 | |||
70 | for (k=0;k<count/4;k++) { | ||
71 | |||
72 | w2(4); w2(5); | ||
73 | w0(0); a = r1(); w0(1); b = r1(); | ||
74 | w0(3); c = r1(); w0(2); d = r1(); | ||
75 | buf[4*k+0] = j44(a,b); | ||
76 | buf[4*k+1] = j44(d,c); | ||
77 | |||
78 | w2(4); w2(5); | ||
79 | a = r1(); w0(3); b = r1(); | ||
80 | w0(1); c = r1(); w0(0); d = r1(); | ||
81 | buf[4*k+2] = j44(d,c); | ||
82 | buf[4*k+3] = j44(a,b); | ||
83 | |||
84 | } | ||
85 | |||
86 | w2(4); | ||
87 | |||
88 | } | ||
89 | |||
90 | static void fit2_write_block( PIA *pi, char * buf, int count ) | ||
91 | |||
92 | { int k; | ||
93 | |||
94 | |||
95 | w2(0xc); w0(0); | ||
96 | for (k=0;k<count/2;k++) { | ||
97 | w2(4); w0(buf[2*k]); | ||
98 | w2(5); w0(buf[2*k+1]); | ||
99 | } | ||
100 | w2(4); | ||
101 | } | ||
102 | |||
103 | static void fit2_connect ( PIA *pi ) | ||
104 | |||
105 | { pi->saved_r0 = r0(); | ||
106 | pi->saved_r2 = r2(); | ||
107 | w2(0xcc); | ||
108 | } | ||
109 | |||
110 | static void fit2_disconnect ( PIA *pi ) | ||
111 | |||
112 | { w0(pi->saved_r0); | ||
113 | w2(pi->saved_r2); | ||
114 | } | ||
115 | |||
116 | static void fit2_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
117 | |||
118 | { printk("%s: fit2 %s, FIT 2000 adapter at 0x%x, delay %d\n", | ||
119 | pi->device,FIT2_VERSION,pi->port,pi->delay); | ||
120 | |||
121 | } | ||
122 | |||
123 | static struct pi_protocol fit2 = { | ||
124 | .owner = THIS_MODULE, | ||
125 | .name = "fit2", | ||
126 | .max_mode = 1, | ||
127 | .epp_first = 2, | ||
128 | .default_delay = 1, | ||
129 | .max_units = 1, | ||
130 | .write_regr = fit2_write_regr, | ||
131 | .read_regr = fit2_read_regr, | ||
132 | .write_block = fit2_write_block, | ||
133 | .read_block = fit2_read_block, | ||
134 | .connect = fit2_connect, | ||
135 | .disconnect = fit2_disconnect, | ||
136 | .log_adapter = fit2_log_adapter, | ||
137 | }; | ||
138 | |||
139 | static int __init fit2_init(void) | ||
140 | { | ||
141 | return pi_register(&fit2)-1; | ||
142 | } | ||
143 | |||
144 | static void __exit fit2_exit(void) | ||
145 | { | ||
146 | pi_unregister(&fit2); | ||
147 | } | ||
148 | |||
149 | MODULE_LICENSE("GPL"); | ||
150 | module_init(fit2_init) | ||
151 | module_exit(fit2_exit) | ||
diff --git a/drivers/block/paride/fit3.c b/drivers/block/paride/fit3.c new file mode 100644 index 000000000000..15400e7bc666 --- /dev/null +++ b/drivers/block/paride/fit3.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | fit3.c (c) 1998 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | fit3.c is a low-level protocol driver for newer models | ||
6 | of the Fidelity International Technology parallel port adapter. | ||
7 | This adapter is used in their TransDisk 3000 portable | ||
8 | hard-drives, as well as CD-ROM, PD-CD and other devices. | ||
9 | |||
10 | The TD-2000 and certain older devices use a different protocol. | ||
11 | Try the fit2 protocol module with them. | ||
12 | |||
13 | NB: The FIT adapters do not appear to support the control | ||
14 | registers. So, we map ALT_STATUS to STATUS and NO-OP writes | ||
15 | to the device control register - this means that IDE reset | ||
16 | will not work on these devices. | ||
17 | |||
18 | */ | ||
19 | |||
20 | #define FIT3_VERSION "1.0" | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <asm/io.h> | ||
29 | |||
30 | #include "paride.h" | ||
31 | |||
32 | #define j44(a,b) (((a>>3)&0x0f)|((b<<1)&0xf0)) | ||
33 | |||
34 | #define w7(byte) {out_p(7,byte);} | ||
35 | #define r7() (in_p(7) & 0xff) | ||
36 | |||
37 | /* cont = 0 - access the IDE register file | ||
38 | cont = 1 - access the IDE command set | ||
39 | |||
40 | */ | ||
41 | |||
42 | static void fit3_write_regr( PIA *pi, int cont, int regr, int val) | ||
43 | |||
44 | { if (cont == 1) return; | ||
45 | |||
46 | switch (pi->mode) { | ||
47 | |||
48 | case 0: | ||
49 | case 1: w2(0xc); w0(regr); w2(0x8); w2(0xc); | ||
50 | w0(val); w2(0xd); | ||
51 | w0(0); w2(0xc); | ||
52 | break; | ||
53 | |||
54 | case 2: w2(0xc); w0(regr); w2(0x8); w2(0xc); | ||
55 | w4(val); w4(0); | ||
56 | w2(0xc); | ||
57 | break; | ||
58 | |||
59 | } | ||
60 | } | ||
61 | |||
62 | static int fit3_read_regr( PIA *pi, int cont, int regr ) | ||
63 | |||
64 | { int a, b; | ||
65 | |||
66 | if (cont) { | ||
67 | if (regr != 6) return 0xff; | ||
68 | regr = 7; | ||
69 | } | ||
70 | |||
71 | switch (pi->mode) { | ||
72 | |||
73 | case 0: w2(0xc); w0(regr + 0x10); w2(0x8); w2(0xc); | ||
74 | w2(0xd); a = r1(); | ||
75 | w2(0xf); b = r1(); | ||
76 | w2(0xc); | ||
77 | return j44(a,b); | ||
78 | |||
79 | case 1: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); | ||
80 | w2(0xec); w2(0xee); w2(0xef); a = r0(); | ||
81 | w2(0xc); | ||
82 | return a; | ||
83 | |||
84 | case 2: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); | ||
85 | w2(0xec); | ||
86 | a = r4(); b = r4(); | ||
87 | w2(0xc); | ||
88 | return a; | ||
89 | |||
90 | } | ||
91 | return -1; | ||
92 | |||
93 | } | ||
94 | |||
95 | static void fit3_read_block( PIA *pi, char * buf, int count ) | ||
96 | |||
97 | { int k, a, b, c, d; | ||
98 | |||
99 | switch (pi->mode) { | ||
100 | |||
101 | case 0: w2(0xc); w0(0x10); w2(0x8); w2(0xc); | ||
102 | for (k=0;k<count/2;k++) { | ||
103 | w2(0xd); a = r1(); | ||
104 | w2(0xf); b = r1(); | ||
105 | w2(0xc); c = r1(); | ||
106 | w2(0xe); d = r1(); | ||
107 | buf[2*k ] = j44(a,b); | ||
108 | buf[2*k+1] = j44(c,d); | ||
109 | } | ||
110 | w2(0xc); | ||
111 | break; | ||
112 | |||
113 | case 1: w2(0xc); w0(0x90); w2(0x8); w2(0xc); | ||
114 | w2(0xec); w2(0xee); | ||
115 | for (k=0;k<count/2;k++) { | ||
116 | w2(0xef); a = r0(); | ||
117 | w2(0xee); b = r0(); | ||
118 | buf[2*k ] = a; | ||
119 | buf[2*k+1] = b; | ||
120 | } | ||
121 | w2(0xec); | ||
122 | w2(0xc); | ||
123 | break; | ||
124 | |||
125 | case 2: w2(0xc); w0(0x90); w2(0x8); w2(0xc); | ||
126 | w2(0xec); | ||
127 | for (k=0;k<count;k++) buf[k] = r4(); | ||
128 | w2(0xc); | ||
129 | break; | ||
130 | |||
131 | } | ||
132 | } | ||
133 | |||
134 | static void fit3_write_block( PIA *pi, char * buf, int count ) | ||
135 | |||
136 | { int k; | ||
137 | |||
138 | switch (pi->mode) { | ||
139 | |||
140 | case 0: | ||
141 | case 1: w2(0xc); w0(0); w2(0x8); w2(0xc); | ||
142 | for (k=0;k<count/2;k++) { | ||
143 | w0(buf[2*k ]); w2(0xd); | ||
144 | w0(buf[2*k+1]); w2(0xc); | ||
145 | } | ||
146 | break; | ||
147 | |||
148 | case 2: w2(0xc); w0(0); w2(0x8); w2(0xc); | ||
149 | for (k=0;k<count;k++) w4(buf[k]); | ||
150 | w2(0xc); | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static void fit3_connect ( PIA *pi ) | ||
156 | |||
157 | { pi->saved_r0 = r0(); | ||
158 | pi->saved_r2 = r2(); | ||
159 | w2(0xc); w0(0); w2(0xa); | ||
160 | if (pi->mode == 2) { | ||
161 | w2(0xc); w0(0x9); w2(0x8); w2(0xc); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static void fit3_disconnect ( PIA *pi ) | ||
166 | |||
167 | { w2(0xc); w0(0xa); w2(0x8); w2(0xc); | ||
168 | w0(pi->saved_r0); | ||
169 | w2(pi->saved_r2); | ||
170 | } | ||
171 | |||
172 | static void fit3_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
173 | |||
174 | { char *mode_string[3] = {"4-bit","8-bit","EPP"}; | ||
175 | |||
176 | printk("%s: fit3 %s, FIT 3000 adapter at 0x%x, " | ||
177 | "mode %d (%s), delay %d\n", | ||
178 | pi->device,FIT3_VERSION,pi->port, | ||
179 | pi->mode,mode_string[pi->mode],pi->delay); | ||
180 | |||
181 | } | ||
182 | |||
183 | static struct pi_protocol fit3 = { | ||
184 | .owner = THIS_MODULE, | ||
185 | .name = "fit3", | ||
186 | .max_mode = 3, | ||
187 | .epp_first = 2, | ||
188 | .default_delay = 1, | ||
189 | .max_units = 1, | ||
190 | .write_regr = fit3_write_regr, | ||
191 | .read_regr = fit3_read_regr, | ||
192 | .write_block = fit3_write_block, | ||
193 | .read_block = fit3_read_block, | ||
194 | .connect = fit3_connect, | ||
195 | .disconnect = fit3_disconnect, | ||
196 | .log_adapter = fit3_log_adapter, | ||
197 | }; | ||
198 | |||
199 | static int __init fit3_init(void) | ||
200 | { | ||
201 | return pi_register(&fit3)-1; | ||
202 | } | ||
203 | |||
204 | static void __exit fit3_exit(void) | ||
205 | { | ||
206 | pi_unregister(&fit3); | ||
207 | } | ||
208 | |||
209 | MODULE_LICENSE("GPL"); | ||
210 | module_init(fit3_init) | ||
211 | module_exit(fit3_exit) | ||
diff --git a/drivers/block/paride/friq.c b/drivers/block/paride/friq.c new file mode 100644 index 000000000000..5ea2904d2815 --- /dev/null +++ b/drivers/block/paride/friq.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | friq.c (c) 1998 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License | ||
4 | |||
5 | friq.c is a low-level protocol driver for the Freecom "IQ" | ||
6 | parallel port IDE adapter. Early versions of this adapter | ||
7 | use the 'frpw' protocol. | ||
8 | |||
9 | Freecom uses this adapter in a battery powered external | ||
10 | CD-ROM drive. It is also used in LS-120 drives by | ||
11 | Maxell and Panasonic, and other devices. | ||
12 | |||
13 | The battery powered drive requires software support to | ||
14 | control the power to the drive. This module enables the | ||
15 | drive power when the high level driver (pcd) is loaded | ||
16 | and disables it when the module is unloaded. Note, if | ||
17 | the friq module is built in to the kernel, the power | ||
18 | will never be switched off, so other means should be | ||
19 | used to conserve battery power. | ||
20 | |||
21 | */ | ||
22 | |||
23 | /* Changes: | ||
24 | |||
25 | 1.01 GRG 1998.12.20 Added support for soft power switch | ||
26 | */ | ||
27 | |||
28 | #define FRIQ_VERSION "1.01" | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/types.h> | ||
35 | #include <linux/wait.h> | ||
36 | #include <asm/io.h> | ||
37 | |||
38 | #include "paride.h" | ||
39 | |||
40 | #define CMD(x) w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\ | ||
41 | w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x); | ||
42 | |||
43 | #define j44(l,h) (((l>>4)&0x0f)|(h&0xf0)) | ||
44 | |||
45 | /* cont = 0 - access the IDE register file | ||
46 | cont = 1 - access the IDE command set | ||
47 | */ | ||
48 | |||
49 | static int cont_map[2] = { 0x08, 0x10 }; | ||
50 | |||
51 | static int friq_read_regr( PIA *pi, int cont, int regr ) | ||
52 | |||
53 | { int h,l,r; | ||
54 | |||
55 | r = regr + cont_map[cont]; | ||
56 | |||
57 | CMD(r); | ||
58 | w2(6); l = r1(); | ||
59 | w2(4); h = r1(); | ||
60 | w2(4); | ||
61 | |||
62 | return j44(l,h); | ||
63 | |||
64 | } | ||
65 | |||
66 | static void friq_write_regr( PIA *pi, int cont, int regr, int val) | ||
67 | |||
68 | { int r; | ||
69 | |||
70 | r = regr + cont_map[cont]; | ||
71 | |||
72 | CMD(r); | ||
73 | w0(val); | ||
74 | w2(5);w2(7);w2(5);w2(4); | ||
75 | } | ||
76 | |||
77 | static void friq_read_block_int( PIA *pi, char * buf, int count, int regr ) | ||
78 | |||
79 | { int h, l, k, ph; | ||
80 | |||
81 | switch(pi->mode) { | ||
82 | |||
83 | case 0: CMD(regr); | ||
84 | for (k=0;k<count;k++) { | ||
85 | w2(6); l = r1(); | ||
86 | w2(4); h = r1(); | ||
87 | buf[k] = j44(l,h); | ||
88 | } | ||
89 | w2(4); | ||
90 | break; | ||
91 | |||
92 | case 1: ph = 2; | ||
93 | CMD(regr+0xc0); | ||
94 | w0(0xff); | ||
95 | for (k=0;k<count;k++) { | ||
96 | w2(0xa4 + ph); | ||
97 | buf[k] = r0(); | ||
98 | ph = 2 - ph; | ||
99 | } | ||
100 | w2(0xac); w2(0xa4); w2(4); | ||
101 | break; | ||
102 | |||
103 | case 2: CMD(regr+0x80); | ||
104 | for (k=0;k<count-2;k++) buf[k] = r4(); | ||
105 | w2(0xac); w2(0xa4); | ||
106 | buf[count-2] = r4(); | ||
107 | buf[count-1] = r4(); | ||
108 | w2(4); | ||
109 | break; | ||
110 | |||
111 | case 3: CMD(regr+0x80); | ||
112 | for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w(); | ||
113 | w2(0xac); w2(0xa4); | ||
114 | buf[count-2] = r4(); | ||
115 | buf[count-1] = r4(); | ||
116 | w2(4); | ||
117 | break; | ||
118 | |||
119 | case 4: CMD(regr+0x80); | ||
120 | for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l(); | ||
121 | buf[count-4] = r4(); | ||
122 | buf[count-3] = r4(); | ||
123 | w2(0xac); w2(0xa4); | ||
124 | buf[count-2] = r4(); | ||
125 | buf[count-1] = r4(); | ||
126 | w2(4); | ||
127 | break; | ||
128 | |||
129 | } | ||
130 | } | ||
131 | |||
132 | static void friq_read_block( PIA *pi, char * buf, int count) | ||
133 | |||
134 | { friq_read_block_int(pi,buf,count,0x08); | ||
135 | } | ||
136 | |||
137 | static void friq_write_block( PIA *pi, char * buf, int count ) | ||
138 | |||
139 | { int k; | ||
140 | |||
141 | switch(pi->mode) { | ||
142 | |||
143 | case 0: | ||
144 | case 1: CMD(8); w2(5); | ||
145 | for (k=0;k<count;k++) { | ||
146 | w0(buf[k]); | ||
147 | w2(7);w2(5); | ||
148 | } | ||
149 | w2(4); | ||
150 | break; | ||
151 | |||
152 | case 2: CMD(0xc8); w2(5); | ||
153 | for (k=0;k<count;k++) w4(buf[k]); | ||
154 | w2(4); | ||
155 | break; | ||
156 | |||
157 | case 3: CMD(0xc8); w2(5); | ||
158 | for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); | ||
159 | w2(4); | ||
160 | break; | ||
161 | |||
162 | case 4: CMD(0xc8); w2(5); | ||
163 | for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); | ||
164 | w2(4); | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static void friq_connect ( PIA *pi ) | ||
170 | |||
171 | { pi->saved_r0 = r0(); | ||
172 | pi->saved_r2 = r2(); | ||
173 | w2(4); | ||
174 | } | ||
175 | |||
176 | static void friq_disconnect ( PIA *pi ) | ||
177 | |||
178 | { CMD(0x20); | ||
179 | w0(pi->saved_r0); | ||
180 | w2(pi->saved_r2); | ||
181 | } | ||
182 | |||
183 | static int friq_test_proto( PIA *pi, char * scratch, int verbose ) | ||
184 | |||
185 | { int j, k, r; | ||
186 | int e[2] = {0,0}; | ||
187 | |||
188 | pi->saved_r0 = r0(); | ||
189 | w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */ | ||
190 | udelay(500); | ||
191 | w0(pi->saved_r0); | ||
192 | |||
193 | friq_connect(pi); | ||
194 | for (j=0;j<2;j++) { | ||
195 | friq_write_regr(pi,0,6,0xa0+j*0x10); | ||
196 | for (k=0;k<256;k++) { | ||
197 | friq_write_regr(pi,0,2,k^0xaa); | ||
198 | friq_write_regr(pi,0,3,k^0x55); | ||
199 | if (friq_read_regr(pi,0,2) != (k^0xaa)) e[j]++; | ||
200 | } | ||
201 | } | ||
202 | friq_disconnect(pi); | ||
203 | |||
204 | friq_connect(pi); | ||
205 | friq_read_block_int(pi,scratch,512,0x10); | ||
206 | r = 0; | ||
207 | for (k=0;k<128;k++) if (scratch[k] != k) r++; | ||
208 | friq_disconnect(pi); | ||
209 | |||
210 | if (verbose) { | ||
211 | printk("%s: friq: port 0x%x, mode %d, test=(%d,%d,%d)\n", | ||
212 | pi->device,pi->port,pi->mode,e[0],e[1],r); | ||
213 | } | ||
214 | |||
215 | return (r || (e[0] && e[1])); | ||
216 | } | ||
217 | |||
218 | |||
219 | static void friq_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
220 | |||
221 | { char *mode_string[6] = {"4-bit","8-bit", | ||
222 | "EPP-8","EPP-16","EPP-32"}; | ||
223 | |||
224 | printk("%s: friq %s, Freecom IQ ASIC-2 adapter at 0x%x, ", pi->device, | ||
225 | FRIQ_VERSION,pi->port); | ||
226 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
227 | mode_string[pi->mode],pi->delay); | ||
228 | |||
229 | pi->private = 1; | ||
230 | friq_connect(pi); | ||
231 | CMD(0x9e); /* disable sleep timer */ | ||
232 | friq_disconnect(pi); | ||
233 | |||
234 | } | ||
235 | |||
236 | static void friq_release_proto( PIA *pi) | ||
237 | { | ||
238 | if (pi->private) { /* turn off the power */ | ||
239 | friq_connect(pi); | ||
240 | CMD(0x1d); CMD(0x1e); | ||
241 | friq_disconnect(pi); | ||
242 | pi->private = 0; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static struct pi_protocol friq = { | ||
247 | .owner = THIS_MODULE, | ||
248 | .name = "friq", | ||
249 | .max_mode = 5, | ||
250 | .epp_first = 2, | ||
251 | .default_delay = 1, | ||
252 | .max_units = 1, | ||
253 | .write_regr = friq_write_regr, | ||
254 | .read_regr = friq_read_regr, | ||
255 | .write_block = friq_write_block, | ||
256 | .read_block = friq_read_block, | ||
257 | .connect = friq_connect, | ||
258 | .disconnect = friq_disconnect, | ||
259 | .test_proto = friq_test_proto, | ||
260 | .log_adapter = friq_log_adapter, | ||
261 | .release_proto = friq_release_proto, | ||
262 | }; | ||
263 | |||
264 | static int __init friq_init(void) | ||
265 | { | ||
266 | return pi_register(&friq)-1; | ||
267 | } | ||
268 | |||
269 | static void __exit friq_exit(void) | ||
270 | { | ||
271 | pi_unregister(&friq); | ||
272 | } | ||
273 | |||
274 | MODULE_LICENSE("GPL"); | ||
275 | module_init(friq_init) | ||
276 | module_exit(friq_exit) | ||
diff --git a/drivers/block/paride/frpw.c b/drivers/block/paride/frpw.c new file mode 100644 index 000000000000..56b3824b1538 --- /dev/null +++ b/drivers/block/paride/frpw.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | frpw.c (c) 1996-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License | ||
4 | |||
5 | frpw.c is a low-level protocol driver for the Freecom "Power" | ||
6 | parallel port IDE adapter. | ||
7 | |||
8 | Some applications of this adapter may require a "printer" reset | ||
9 | prior to loading the driver. This can be done by loading and | ||
10 | unloading the "lp" driver, or it can be done by this driver | ||
11 | if you define FRPW_HARD_RESET. The latter is not recommended | ||
12 | as it may upset devices on other ports. | ||
13 | |||
14 | */ | ||
15 | |||
16 | /* Changes: | ||
17 | |||
18 | 1.01 GRG 1998.05.06 init_proto, release_proto | ||
19 | fix chip detect | ||
20 | added EPP-16 and EPP-32 | ||
21 | 1.02 GRG 1998.09.23 added hard reset to initialisation process | ||
22 | 1.03 GRG 1998.12.14 made hard reset conditional | ||
23 | |||
24 | */ | ||
25 | |||
26 | #define FRPW_VERSION "1.03" | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <asm/io.h> | ||
35 | |||
36 | #include "paride.h" | ||
37 | |||
38 | #define cec4 w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4); | ||
39 | #define j44(l,h) (((l>>4)&0x0f)|(h&0xf0)) | ||
40 | |||
41 | /* cont = 0 - access the IDE register file | ||
42 | cont = 1 - access the IDE command set | ||
43 | */ | ||
44 | |||
45 | static int cont_map[2] = { 0x08, 0x10 }; | ||
46 | |||
47 | static int frpw_read_regr( PIA *pi, int cont, int regr ) | ||
48 | |||
49 | { int h,l,r; | ||
50 | |||
51 | r = regr + cont_map[cont]; | ||
52 | |||
53 | w2(4); | ||
54 | w0(r); cec4; | ||
55 | w2(6); l = r1(); | ||
56 | w2(4); h = r1(); | ||
57 | w2(4); | ||
58 | |||
59 | return j44(l,h); | ||
60 | |||
61 | } | ||
62 | |||
63 | static void frpw_write_regr( PIA *pi, int cont, int regr, int val) | ||
64 | |||
65 | { int r; | ||
66 | |||
67 | r = regr + cont_map[cont]; | ||
68 | |||
69 | w2(4); w0(r); cec4; | ||
70 | w0(val); | ||
71 | w2(5);w2(7);w2(5);w2(4); | ||
72 | } | ||
73 | |||
74 | static void frpw_read_block_int( PIA *pi, char * buf, int count, int regr ) | ||
75 | |||
76 | { int h, l, k, ph; | ||
77 | |||
78 | switch(pi->mode) { | ||
79 | |||
80 | case 0: w2(4); w0(regr); cec4; | ||
81 | for (k=0;k<count;k++) { | ||
82 | w2(6); l = r1(); | ||
83 | w2(4); h = r1(); | ||
84 | buf[k] = j44(l,h); | ||
85 | } | ||
86 | w2(4); | ||
87 | break; | ||
88 | |||
89 | case 1: ph = 2; | ||
90 | w2(4); w0(regr + 0xc0); cec4; | ||
91 | w0(0xff); | ||
92 | for (k=0;k<count;k++) { | ||
93 | w2(0xa4 + ph); | ||
94 | buf[k] = r0(); | ||
95 | ph = 2 - ph; | ||
96 | } | ||
97 | w2(0xac); w2(0xa4); w2(4); | ||
98 | break; | ||
99 | |||
100 | case 2: w2(4); w0(regr + 0x80); cec4; | ||
101 | for (k=0;k<count;k++) buf[k] = r4(); | ||
102 | w2(0xac); w2(0xa4); | ||
103 | w2(4); | ||
104 | break; | ||
105 | |||
106 | case 3: w2(4); w0(regr + 0x80); cec4; | ||
107 | for (k=0;k<count-2;k++) buf[k] = r4(); | ||
108 | w2(0xac); w2(0xa4); | ||
109 | buf[count-2] = r4(); | ||
110 | buf[count-1] = r4(); | ||
111 | w2(4); | ||
112 | break; | ||
113 | |||
114 | case 4: w2(4); w0(regr + 0x80); cec4; | ||
115 | for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w(); | ||
116 | w2(0xac); w2(0xa4); | ||
117 | buf[count-2] = r4(); | ||
118 | buf[count-1] = r4(); | ||
119 | w2(4); | ||
120 | break; | ||
121 | |||
122 | case 5: w2(4); w0(regr + 0x80); cec4; | ||
123 | for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l(); | ||
124 | buf[count-4] = r4(); | ||
125 | buf[count-3] = r4(); | ||
126 | w2(0xac); w2(0xa4); | ||
127 | buf[count-2] = r4(); | ||
128 | buf[count-1] = r4(); | ||
129 | w2(4); | ||
130 | break; | ||
131 | |||
132 | } | ||
133 | } | ||
134 | |||
135 | static void frpw_read_block( PIA *pi, char * buf, int count) | ||
136 | |||
137 | { frpw_read_block_int(pi,buf,count,0x08); | ||
138 | } | ||
139 | |||
140 | static void frpw_write_block( PIA *pi, char * buf, int count ) | ||
141 | |||
142 | { int k; | ||
143 | |||
144 | switch(pi->mode) { | ||
145 | |||
146 | case 0: | ||
147 | case 1: | ||
148 | case 2: w2(4); w0(8); cec4; w2(5); | ||
149 | for (k=0;k<count;k++) { | ||
150 | w0(buf[k]); | ||
151 | w2(7);w2(5); | ||
152 | } | ||
153 | w2(4); | ||
154 | break; | ||
155 | |||
156 | case 3: w2(4); w0(0xc8); cec4; w2(5); | ||
157 | for (k=0;k<count;k++) w4(buf[k]); | ||
158 | w2(4); | ||
159 | break; | ||
160 | |||
161 | case 4: w2(4); w0(0xc8); cec4; w2(5); | ||
162 | for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); | ||
163 | w2(4); | ||
164 | break; | ||
165 | |||
166 | case 5: w2(4); w0(0xc8); cec4; w2(5); | ||
167 | for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); | ||
168 | w2(4); | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static void frpw_connect ( PIA *pi ) | ||
174 | |||
175 | { pi->saved_r0 = r0(); | ||
176 | pi->saved_r2 = r2(); | ||
177 | w2(4); | ||
178 | } | ||
179 | |||
180 | static void frpw_disconnect ( PIA *pi ) | ||
181 | |||
182 | { w2(4); w0(0x20); cec4; | ||
183 | w0(pi->saved_r0); | ||
184 | w2(pi->saved_r2); | ||
185 | } | ||
186 | |||
187 | /* Stub logic to see if PNP string is available - used to distinguish | ||
188 | between the Xilinx and ASIC implementations of the Freecom adapter. | ||
189 | */ | ||
190 | |||
191 | static int frpw_test_pnp ( PIA *pi ) | ||
192 | |||
193 | /* returns chip_type: 0 = Xilinx, 1 = ASIC */ | ||
194 | |||
195 | { int olddelay, a, b; | ||
196 | |||
197 | #ifdef FRPW_HARD_RESET | ||
198 | w0(0); w2(8); udelay(50); w2(0xc); /* parallel bus reset */ | ||
199 | mdelay(1500); | ||
200 | #endif | ||
201 | |||
202 | olddelay = pi->delay; | ||
203 | pi->delay = 10; | ||
204 | |||
205 | pi->saved_r0 = r0(); | ||
206 | pi->saved_r2 = r2(); | ||
207 | |||
208 | w2(4); w0(4); w2(6); w2(7); | ||
209 | a = r1() & 0xff; w2(4); b = r1() & 0xff; | ||
210 | w2(0xc); w2(0xe); w2(4); | ||
211 | |||
212 | pi->delay = olddelay; | ||
213 | w0(pi->saved_r0); | ||
214 | w2(pi->saved_r2); | ||
215 | |||
216 | return ((~a&0x40) && (b&0x40)); | ||
217 | } | ||
218 | |||
219 | /* We use the pi->private to remember the result of the PNP test. | ||
220 | To make this work, private = port*2 + chip. Yes, I know it's | ||
221 | a hack :-( | ||
222 | */ | ||
223 | |||
224 | static int frpw_test_proto( PIA *pi, char * scratch, int verbose ) | ||
225 | |||
226 | { int j, k, r; | ||
227 | int e[2] = {0,0}; | ||
228 | |||
229 | if ((pi->private>>1) != pi->port) | ||
230 | pi->private = frpw_test_pnp(pi) + 2*pi->port; | ||
231 | |||
232 | if (((pi->private%2) == 0) && (pi->mode > 2)) { | ||
233 | if (verbose) | ||
234 | printk("%s: frpw: Xilinx does not support mode %d\n", | ||
235 | pi->device, pi->mode); | ||
236 | return 1; | ||
237 | } | ||
238 | |||
239 | if (((pi->private%2) == 1) && (pi->mode == 2)) { | ||
240 | if (verbose) | ||
241 | printk("%s: frpw: ASIC does not support mode 2\n", | ||
242 | pi->device); | ||
243 | return 1; | ||
244 | } | ||
245 | |||
246 | frpw_connect(pi); | ||
247 | for (j=0;j<2;j++) { | ||
248 | frpw_write_regr(pi,0,6,0xa0+j*0x10); | ||
249 | for (k=0;k<256;k++) { | ||
250 | frpw_write_regr(pi,0,2,k^0xaa); | ||
251 | frpw_write_regr(pi,0,3,k^0x55); | ||
252 | if (frpw_read_regr(pi,0,2) != (k^0xaa)) e[j]++; | ||
253 | } | ||
254 | } | ||
255 | frpw_disconnect(pi); | ||
256 | |||
257 | frpw_connect(pi); | ||
258 | frpw_read_block_int(pi,scratch,512,0x10); | ||
259 | r = 0; | ||
260 | for (k=0;k<128;k++) if (scratch[k] != k) r++; | ||
261 | frpw_disconnect(pi); | ||
262 | |||
263 | if (verbose) { | ||
264 | printk("%s: frpw: port 0x%x, chip %ld, mode %d, test=(%d,%d,%d)\n", | ||
265 | pi->device,pi->port,(pi->private%2),pi->mode,e[0],e[1],r); | ||
266 | } | ||
267 | |||
268 | return (r || (e[0] && e[1])); | ||
269 | } | ||
270 | |||
271 | |||
272 | static void frpw_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
273 | |||
274 | { char *mode_string[6] = {"4-bit","8-bit","EPP", | ||
275 | "EPP-8","EPP-16","EPP-32"}; | ||
276 | |||
277 | printk("%s: frpw %s, Freecom (%s) adapter at 0x%x, ", pi->device, | ||
278 | FRPW_VERSION,((pi->private%2) == 0)?"Xilinx":"ASIC",pi->port); | ||
279 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
280 | mode_string[pi->mode],pi->delay); | ||
281 | |||
282 | } | ||
283 | |||
284 | static struct pi_protocol frpw = { | ||
285 | .owner = THIS_MODULE, | ||
286 | .name = "frpw", | ||
287 | .max_mode = 6, | ||
288 | .epp_first = 2, | ||
289 | .default_delay = 2, | ||
290 | .max_units = 1, | ||
291 | .write_regr = frpw_write_regr, | ||
292 | .read_regr = frpw_read_regr, | ||
293 | .write_block = frpw_write_block, | ||
294 | .read_block = frpw_read_block, | ||
295 | .connect = frpw_connect, | ||
296 | .disconnect = frpw_disconnect, | ||
297 | .test_proto = frpw_test_proto, | ||
298 | .log_adapter = frpw_log_adapter, | ||
299 | }; | ||
300 | |||
301 | static int __init frpw_init(void) | ||
302 | { | ||
303 | return pi_register(&frpw)-1; | ||
304 | } | ||
305 | |||
306 | static void __exit frpw_exit(void) | ||
307 | { | ||
308 | pi_unregister(&frpw); | ||
309 | } | ||
310 | |||
311 | MODULE_LICENSE("GPL"); | ||
312 | module_init(frpw_init) | ||
313 | module_exit(frpw_exit) | ||
diff --git a/drivers/block/paride/jumbo b/drivers/block/paride/jumbo new file mode 100644 index 000000000000..e793b9cb7e72 --- /dev/null +++ b/drivers/block/paride/jumbo | |||
@@ -0,0 +1,70 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # This script can be used to build "jumbo" modules that contain the | ||
4 | # base PARIDE support, one protocol module and one high-level driver. | ||
5 | # | ||
6 | echo -n "High level driver [pcd] : " | ||
7 | read X | ||
8 | HLD=${X:-pcd} | ||
9 | # | ||
10 | echo -n "Protocol module [bpck] : " | ||
11 | read X | ||
12 | PROTO=${X:-bpck} | ||
13 | # | ||
14 | echo -n "Use MODVERSIONS [y] ? " | ||
15 | read X | ||
16 | UMODV=${X:-y} | ||
17 | # | ||
18 | echo -n "For SMP kernel [n] ? " | ||
19 | read X | ||
20 | USMP=${X:-n} | ||
21 | # | ||
22 | echo -n "Support PARPORT [n] ? " | ||
23 | read X | ||
24 | UPARP=${X:-n} | ||
25 | # | ||
26 | echo | ||
27 | # | ||
28 | case $USMP in | ||
29 | y* | Y* ) FSMP="-DCONFIG_SMP" | ||
30 | ;; | ||
31 | *) FSMP="" | ||
32 | ;; | ||
33 | esac | ||
34 | # | ||
35 | MODI="-include ../../../include/linux/modversions.h" | ||
36 | # | ||
37 | case $UMODV in | ||
38 | y* | Y* ) FMODV="-DMODVERSIONS $MODI" | ||
39 | ;; | ||
40 | *) FMODV="" | ||
41 | ;; | ||
42 | esac | ||
43 | # | ||
44 | case $UPARP in | ||
45 | y* | Y* ) FPARP="-DCONFIG_PARPORT" | ||
46 | ;; | ||
47 | *) FPARP="" | ||
48 | ;; | ||
49 | esac | ||
50 | # | ||
51 | TARG=$HLD-$PROTO.o | ||
52 | FPROTO=-DCONFIG_PARIDE_`echo "$PROTO" | tr [a-z] [A-Z]` | ||
53 | FK="-D__KERNEL__ -I ../../../include" | ||
54 | FLCH=-D_LINUX_CONFIG_H | ||
55 | # | ||
56 | echo cc $FK $FSMP $FLCH $FPARP $FPROTO $FMODV -Wall -O2 -o Jb.o -c paride.c | ||
57 | cc $FK $FSMP $FLCH $FPARP $FPROTO $FMODV -Wall -O2 -o Jb.o -c paride.c | ||
58 | # | ||
59 | echo cc $FK $FSMP $FMODV -Wall -O2 -o Jp.o -c $PROTO.c | ||
60 | cc $FK $FSMP $FMODV -Wall -O2 -o Jp.o -c $PROTO.c | ||
61 | # | ||
62 | echo cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c | ||
63 | cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c | ||
64 | # | ||
65 | echo ld -r -o $TARG Jp.o Jb.o Jd.o | ||
66 | ld -r -o $TARG Jp.o Jb.o Jd.o | ||
67 | # | ||
68 | # | ||
69 | rm Jp.o Jb.o Jd.o | ||
70 | # | ||
diff --git a/drivers/block/paride/kbic.c b/drivers/block/paride/kbic.c new file mode 100644 index 000000000000..d983bcea76fe --- /dev/null +++ b/drivers/block/paride/kbic.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | kbic.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is a low-level driver for the KBIC-951A and KBIC-971A | ||
6 | parallel to IDE adapter chips from KingByte Information Systems. | ||
7 | |||
8 | The chips are almost identical, however, the wakeup code | ||
9 | required for the 971A interferes with the correct operation of | ||
10 | the 951A, so this driver registers itself twice, once for | ||
11 | each chip. | ||
12 | |||
13 | */ | ||
14 | |||
15 | /* Changes: | ||
16 | |||
17 | 1.01 GRG 1998.05.06 init_proto, release_proto | ||
18 | |||
19 | */ | ||
20 | |||
21 | #define KBIC_VERSION "1.01" | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/wait.h> | ||
29 | #include <asm/io.h> | ||
30 | |||
31 | #include "paride.h" | ||
32 | |||
33 | #define r12w() (delay_p,inw(pi->port+1)&0xffff) | ||
34 | |||
35 | #define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88) | ||
36 | #define j53(w) (((w>>3)&0x1f)|((w>>4)&0xe0)) | ||
37 | |||
38 | |||
39 | /* cont = 0 - access the IDE register file | ||
40 | cont = 1 - access the IDE command set | ||
41 | */ | ||
42 | |||
43 | static int cont_map[2] = { 0x80, 0x40 }; | ||
44 | |||
45 | static int kbic_read_regr( PIA *pi, int cont, int regr ) | ||
46 | |||
47 | { int a, b, s; | ||
48 | |||
49 | s = cont_map[cont]; | ||
50 | |||
51 | switch (pi->mode) { | ||
52 | |||
53 | case 0: w0(regr|0x18|s); w2(4); w2(6); w2(4); w2(1); w0(8); | ||
54 | a = r1(); w0(0x28); b = r1(); w2(4); | ||
55 | return j44(a,b); | ||
56 | |||
57 | case 1: w0(regr|0x38|s); w2(4); w2(6); w2(4); w2(5); w0(8); | ||
58 | a = r12w(); w2(4); | ||
59 | return j53(a); | ||
60 | |||
61 | case 2: w0(regr|0x08|s); w2(4); w2(6); w2(4); w2(0xa5); w2(0xa1); | ||
62 | a = r0(); w2(4); | ||
63 | return a; | ||
64 | |||
65 | case 3: | ||
66 | case 4: | ||
67 | case 5: w0(0x20|s); w2(4); w2(6); w2(4); w3(regr); | ||
68 | a = r4(); b = r4(); w2(4); w2(0); w2(4); | ||
69 | return a; | ||
70 | |||
71 | } | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | static void kbic_write_regr( PIA *pi, int cont, int regr, int val) | ||
76 | |||
77 | { int s; | ||
78 | |||
79 | s = cont_map[cont]; | ||
80 | |||
81 | switch (pi->mode) { | ||
82 | |||
83 | case 0: | ||
84 | case 1: | ||
85 | case 2: w0(regr|0x10|s); w2(4); w2(6); w2(4); | ||
86 | w0(val); w2(5); w2(4); | ||
87 | break; | ||
88 | |||
89 | case 3: | ||
90 | case 4: | ||
91 | case 5: w0(0x20|s); w2(4); w2(6); w2(4); w3(regr); | ||
92 | w4(val); w4(val); | ||
93 | w2(4); w2(0); w2(4); | ||
94 | break; | ||
95 | |||
96 | } | ||
97 | } | ||
98 | |||
99 | static void k951_connect ( PIA *pi ) | ||
100 | |||
101 | { pi->saved_r0 = r0(); | ||
102 | pi->saved_r2 = r2(); | ||
103 | w2(4); | ||
104 | } | ||
105 | |||
106 | static void k951_disconnect ( PIA *pi ) | ||
107 | |||
108 | { w0(pi->saved_r0); | ||
109 | w2(pi->saved_r2); | ||
110 | } | ||
111 | |||
112 | #define CCP(x) w2(0xc4);w0(0xaa);w0(0x55);w0(0);w0(0xff);w0(0x87);\ | ||
113 | w0(0x78);w0(x);w2(0xc5);w2(0xc4);w0(0xff); | ||
114 | |||
115 | static void k971_connect ( PIA *pi ) | ||
116 | |||
117 | { pi->saved_r0 = r0(); | ||
118 | pi->saved_r2 = r2(); | ||
119 | CCP(0x20); | ||
120 | w2(4); | ||
121 | } | ||
122 | |||
123 | static void k971_disconnect ( PIA *pi ) | ||
124 | |||
125 | { CCP(0x30); | ||
126 | w0(pi->saved_r0); | ||
127 | w2(pi->saved_r2); | ||
128 | } | ||
129 | |||
130 | /* counts must be congruent to 0 MOD 4, but all known applications | ||
131 | have this property. | ||
132 | */ | ||
133 | |||
134 | static void kbic_read_block( PIA *pi, char * buf, int count ) | ||
135 | |||
136 | { int k, a, b; | ||
137 | |||
138 | switch (pi->mode) { | ||
139 | |||
140 | case 0: w0(0x98); w2(4); w2(6); w2(4); | ||
141 | for (k=0;k<count/2;k++) { | ||
142 | w2(1); w0(8); a = r1(); | ||
143 | w0(0x28); b = r1(); | ||
144 | buf[2*k] = j44(a,b); | ||
145 | w2(5); b = r1(); | ||
146 | w0(8); a = r1(); | ||
147 | buf[2*k+1] = j44(a,b); | ||
148 | w2(4); | ||
149 | } | ||
150 | break; | ||
151 | |||
152 | case 1: w0(0xb8); w2(4); w2(6); w2(4); | ||
153 | for (k=0;k<count/4;k++) { | ||
154 | w0(0xb8); | ||
155 | w2(4); w2(5); | ||
156 | w0(8); buf[4*k] = j53(r12w()); | ||
157 | w0(0xb8); buf[4*k+1] = j53(r12w()); | ||
158 | w2(4); w2(5); | ||
159 | buf[4*k+3] = j53(r12w()); | ||
160 | w0(8); buf[4*k+2] = j53(r12w()); | ||
161 | } | ||
162 | w2(4); | ||
163 | break; | ||
164 | |||
165 | case 2: w0(0x88); w2(4); w2(6); w2(4); | ||
166 | for (k=0;k<count/2;k++) { | ||
167 | w2(0xa0); w2(0xa1); buf[2*k] = r0(); | ||
168 | w2(0xa5); buf[2*k+1] = r0(); | ||
169 | } | ||
170 | w2(4); | ||
171 | break; | ||
172 | |||
173 | case 3: w0(0xa0); w2(4); w2(6); w2(4); w3(0); | ||
174 | for (k=0;k<count;k++) buf[k] = r4(); | ||
175 | w2(4); w2(0); w2(4); | ||
176 | break; | ||
177 | |||
178 | case 4: w0(0xa0); w2(4); w2(6); w2(4); w3(0); | ||
179 | for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w(); | ||
180 | w2(4); w2(0); w2(4); | ||
181 | break; | ||
182 | |||
183 | case 5: w0(0xa0); w2(4); w2(6); w2(4); w3(0); | ||
184 | for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l(); | ||
185 | w2(4); w2(0); w2(4); | ||
186 | break; | ||
187 | |||
188 | |||
189 | } | ||
190 | } | ||
191 | |||
192 | static void kbic_write_block( PIA *pi, char * buf, int count ) | ||
193 | |||
194 | { int k; | ||
195 | |||
196 | switch (pi->mode) { | ||
197 | |||
198 | case 0: | ||
199 | case 1: | ||
200 | case 2: w0(0x90); w2(4); w2(6); w2(4); | ||
201 | for(k=0;k<count/2;k++) { | ||
202 | w0(buf[2*k+1]); w2(0); w2(4); | ||
203 | w0(buf[2*k]); w2(5); w2(4); | ||
204 | } | ||
205 | break; | ||
206 | |||
207 | case 3: w0(0xa0); w2(4); w2(6); w2(4); w3(0); | ||
208 | for(k=0;k<count/2;k++) { | ||
209 | w4(buf[2*k+1]); | ||
210 | w4(buf[2*k]); | ||
211 | } | ||
212 | w2(4); w2(0); w2(4); | ||
213 | break; | ||
214 | |||
215 | case 4: w0(0xa0); w2(4); w2(6); w2(4); w3(0); | ||
216 | for(k=0;k<count/2;k++) w4w(pi_swab16(buf,k)); | ||
217 | w2(4); w2(0); w2(4); | ||
218 | break; | ||
219 | |||
220 | case 5: w0(0xa0); w2(4); w2(6); w2(4); w3(0); | ||
221 | for(k=0;k<count/4;k++) w4l(pi_swab32(buf,k)); | ||
222 | w2(4); w2(0); w2(4); | ||
223 | break; | ||
224 | |||
225 | } | ||
226 | |||
227 | } | ||
228 | |||
229 | static void kbic_log_adapter( PIA *pi, char * scratch, | ||
230 | int verbose, char * chip ) | ||
231 | |||
232 | { char *mode_string[6] = {"4-bit","5/3","8-bit", | ||
233 | "EPP-8","EPP_16","EPP-32"}; | ||
234 | |||
235 | printk("%s: kbic %s, KingByte %s at 0x%x, ", | ||
236 | pi->device,KBIC_VERSION,chip,pi->port); | ||
237 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
238 | mode_string[pi->mode],pi->delay); | ||
239 | |||
240 | } | ||
241 | |||
242 | static void k951_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
243 | |||
244 | { kbic_log_adapter(pi,scratch,verbose,"KBIC-951A"); | ||
245 | } | ||
246 | |||
247 | static void k971_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
248 | |||
249 | { kbic_log_adapter(pi,scratch,verbose,"KBIC-971A"); | ||
250 | } | ||
251 | |||
252 | static struct pi_protocol k951 = { | ||
253 | .owner = THIS_MODULE, | ||
254 | .name = "k951", | ||
255 | .max_mode = 6, | ||
256 | .epp_first = 3, | ||
257 | .default_delay = 1, | ||
258 | .max_units = 1, | ||
259 | .write_regr = kbic_write_regr, | ||
260 | .read_regr = kbic_read_regr, | ||
261 | .write_block = kbic_write_block, | ||
262 | .read_block = kbic_read_block, | ||
263 | .connect = k951_connect, | ||
264 | .disconnect = k951_disconnect, | ||
265 | .log_adapter = k951_log_adapter, | ||
266 | }; | ||
267 | |||
268 | static struct pi_protocol k971 = { | ||
269 | .owner = THIS_MODULE, | ||
270 | .name = "k971", | ||
271 | .max_mode = 6, | ||
272 | .epp_first = 3, | ||
273 | .default_delay = 1, | ||
274 | .max_units = 1, | ||
275 | .write_regr = kbic_write_regr, | ||
276 | .read_regr = kbic_read_regr, | ||
277 | .write_block = kbic_write_block, | ||
278 | .read_block = kbic_read_block, | ||
279 | .connect = k971_connect, | ||
280 | .disconnect = k971_disconnect, | ||
281 | .log_adapter = k971_log_adapter, | ||
282 | }; | ||
283 | |||
284 | static int __init kbic_init(void) | ||
285 | { | ||
286 | return (pi_register(&k951)||pi_register(&k971))-1; | ||
287 | } | ||
288 | |||
289 | static void __exit kbic_exit(void) | ||
290 | { | ||
291 | pi_unregister(&k951); | ||
292 | pi_unregister(&k971); | ||
293 | } | ||
294 | |||
295 | MODULE_LICENSE("GPL"); | ||
296 | module_init(kbic_init) | ||
297 | module_exit(kbic_exit) | ||
diff --git a/drivers/block/paride/ktti.c b/drivers/block/paride/ktti.c new file mode 100644 index 000000000000..6c7edbfba9a0 --- /dev/null +++ b/drivers/block/paride/ktti.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | ktti.c (c) 1998 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | ktti.c is a low-level protocol driver for the KT Technology | ||
6 | parallel port adapter. This adapter is used in the "PHd" | ||
7 | portable hard-drives. As far as I can tell, this device | ||
8 | supports 4-bit mode _only_. | ||
9 | |||
10 | */ | ||
11 | |||
12 | #define KTTI_VERSION "1.0" | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <asm/io.h> | ||
21 | |||
22 | #include "paride.h" | ||
23 | |||
24 | #define j44(a,b) (((a>>4)&0x0f)|(b&0xf0)) | ||
25 | |||
26 | /* cont = 0 - access the IDE register file | ||
27 | cont = 1 - access the IDE command set | ||
28 | */ | ||
29 | |||
30 | static int cont_map[2] = { 0x10, 0x08 }; | ||
31 | |||
32 | static void ktti_write_regr( PIA *pi, int cont, int regr, int val) | ||
33 | |||
34 | { int r; | ||
35 | |||
36 | r = regr + cont_map[cont]; | ||
37 | |||
38 | w0(r); w2(0xb); w2(0xa); w2(3); w2(6); | ||
39 | w0(val); w2(3); w0(0); w2(6); w2(0xb); | ||
40 | } | ||
41 | |||
42 | static int ktti_read_regr( PIA *pi, int cont, int regr ) | ||
43 | |||
44 | { int a, b, r; | ||
45 | |||
46 | r = regr + cont_map[cont]; | ||
47 | |||
48 | w0(r); w2(0xb); w2(0xa); w2(9); w2(0xc); w2(9); | ||
49 | a = r1(); w2(0xc); b = r1(); w2(9); w2(0xc); w2(9); | ||
50 | return j44(a,b); | ||
51 | |||
52 | } | ||
53 | |||
54 | static void ktti_read_block( PIA *pi, char * buf, int count ) | ||
55 | |||
56 | { int k, a, b; | ||
57 | |||
58 | for (k=0;k<count/2;k++) { | ||
59 | w0(0x10); w2(0xb); w2(0xa); w2(9); w2(0xc); w2(9); | ||
60 | a = r1(); w2(0xc); b = r1(); w2(9); | ||
61 | buf[2*k] = j44(a,b); | ||
62 | a = r1(); w2(0xc); b = r1(); w2(9); | ||
63 | buf[2*k+1] = j44(a,b); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static void ktti_write_block( PIA *pi, char * buf, int count ) | ||
68 | |||
69 | { int k; | ||
70 | |||
71 | for (k=0;k<count/2;k++) { | ||
72 | w0(0x10); w2(0xb); w2(0xa); w2(3); w2(6); | ||
73 | w0(buf[2*k]); w2(3); | ||
74 | w0(buf[2*k+1]); w2(6); | ||
75 | w2(0xb); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static void ktti_connect ( PIA *pi ) | ||
80 | |||
81 | { pi->saved_r0 = r0(); | ||
82 | pi->saved_r2 = r2(); | ||
83 | w2(0xb); w2(0xa); w0(0); w2(3); w2(6); | ||
84 | } | ||
85 | |||
86 | static void ktti_disconnect ( PIA *pi ) | ||
87 | |||
88 | { w2(0xb); w2(0xa); w0(0xa0); w2(3); w2(4); | ||
89 | w0(pi->saved_r0); | ||
90 | w2(pi->saved_r2); | ||
91 | } | ||
92 | |||
93 | static void ktti_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
94 | |||
95 | { printk("%s: ktti %s, KT adapter at 0x%x, delay %d\n", | ||
96 | pi->device,KTTI_VERSION,pi->port,pi->delay); | ||
97 | |||
98 | } | ||
99 | |||
100 | static struct pi_protocol ktti = { | ||
101 | .owner = THIS_MODULE, | ||
102 | .name = "ktti", | ||
103 | .max_mode = 1, | ||
104 | .epp_first = 2, | ||
105 | .default_delay = 1, | ||
106 | .max_units = 1, | ||
107 | .write_regr = ktti_write_regr, | ||
108 | .read_regr = ktti_read_regr, | ||
109 | .write_block = ktti_write_block, | ||
110 | .read_block = ktti_read_block, | ||
111 | .connect = ktti_connect, | ||
112 | .disconnect = ktti_disconnect, | ||
113 | .log_adapter = ktti_log_adapter, | ||
114 | }; | ||
115 | |||
116 | static int __init ktti_init(void) | ||
117 | { | ||
118 | return pi_register(&ktti)-1; | ||
119 | } | ||
120 | |||
121 | static void __exit ktti_exit(void) | ||
122 | { | ||
123 | pi_unregister(&ktti); | ||
124 | } | ||
125 | |||
126 | MODULE_LICENSE("GPL"); | ||
127 | module_init(ktti_init) | ||
128 | module_exit(ktti_exit) | ||
diff --git a/drivers/block/paride/mkd b/drivers/block/paride/mkd new file mode 100644 index 000000000000..971f099b40aa --- /dev/null +++ b/drivers/block/paride/mkd | |||
@@ -0,0 +1,30 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # mkd -- a script to create the device special files for the PARIDE subsystem | ||
4 | # | ||
5 | # block devices: pd (45), pcd (46), pf (47) | ||
6 | # character devices: pt (96), pg (97) | ||
7 | # | ||
8 | function mkdev { | ||
9 | mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1 | ||
10 | } | ||
11 | # | ||
12 | function pd { | ||
13 | D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) ) | ||
14 | mkdev pd$D b 45 $[ $1 * 16 ] | ||
15 | for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
16 | do mkdev pd$D$P b 45 $[ $1 * 16 + $P ] | ||
17 | done | ||
18 | } | ||
19 | # | ||
20 | cd /dev | ||
21 | # | ||
22 | for u in 0 1 2 3 ; do pd $u ; done | ||
23 | for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done | ||
24 | for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done | ||
25 | for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done | ||
26 | for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done | ||
27 | for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done | ||
28 | # | ||
29 | # end of mkd | ||
30 | |||
diff --git a/drivers/block/paride/on20.c b/drivers/block/paride/on20.c new file mode 100644 index 000000000000..9f8e01096809 --- /dev/null +++ b/drivers/block/paride/on20.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | on20.c (c) 1996-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | on20.c is a low-level protocol driver for the | ||
6 | Onspec 90c20 parallel to IDE adapter. | ||
7 | */ | ||
8 | |||
9 | /* Changes: | ||
10 | |||
11 | 1.01 GRG 1998.05.06 init_proto, release_proto | ||
12 | |||
13 | */ | ||
14 | |||
15 | #define ON20_VERSION "1.01" | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/wait.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | #include "paride.h" | ||
26 | |||
27 | #define op(f) w2(4);w0(f);w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4); | ||
28 | #define vl(v) w2(4);w0(v);w2(5);w2(7);w2(5);w2(4); | ||
29 | |||
30 | #define j44(a,b) (((a>>4)&0x0f)|(b&0xf0)) | ||
31 | |||
32 | /* cont = 0 - access the IDE register file | ||
33 | cont = 1 - access the IDE command set | ||
34 | */ | ||
35 | |||
36 | static int on20_read_regr( PIA *pi, int cont, int regr ) | ||
37 | |||
38 | { int h,l, r ; | ||
39 | |||
40 | r = (regr<<2) + 1 + cont; | ||
41 | |||
42 | op(1); vl(r); op(0); | ||
43 | |||
44 | switch (pi->mode) { | ||
45 | |||
46 | case 0: w2(4); w2(6); l = r1(); | ||
47 | w2(4); w2(6); h = r1(); | ||
48 | w2(4); w2(6); w2(4); w2(6); w2(4); | ||
49 | return j44(l,h); | ||
50 | |||
51 | case 1: w2(4); w2(0x26); r = r0(); | ||
52 | w2(4); w2(0x26); w2(4); | ||
53 | return r; | ||
54 | |||
55 | } | ||
56 | return -1; | ||
57 | } | ||
58 | |||
59 | static void on20_write_regr( PIA *pi, int cont, int regr, int val ) | ||
60 | |||
61 | { int r; | ||
62 | |||
63 | r = (regr<<2) + 1 + cont; | ||
64 | |||
65 | op(1); vl(r); | ||
66 | op(0); vl(val); | ||
67 | op(0); vl(val); | ||
68 | } | ||
69 | |||
70 | static void on20_connect ( PIA *pi) | ||
71 | |||
72 | { pi->saved_r0 = r0(); | ||
73 | pi->saved_r2 = r2(); | ||
74 | |||
75 | w2(4);w0(0);w2(0xc);w2(4);w2(6);w2(4);w2(6);w2(4); | ||
76 | if (pi->mode) { op(2); vl(8); op(2); vl(9); } | ||
77 | else { op(2); vl(0); op(2); vl(8); } | ||
78 | } | ||
79 | |||
80 | static void on20_disconnect ( PIA *pi ) | ||
81 | |||
82 | { w2(4);w0(7);w2(4);w2(0xc);w2(4); | ||
83 | w0(pi->saved_r0); | ||
84 | w2(pi->saved_r2); | ||
85 | } | ||
86 | |||
87 | static void on20_read_block( PIA *pi, char * buf, int count ) | ||
88 | |||
89 | { int k, l, h; | ||
90 | |||
91 | op(1); vl(1); op(0); | ||
92 | |||
93 | for (k=0;k<count;k++) | ||
94 | if (pi->mode) { | ||
95 | w2(4); w2(0x26); buf[k] = r0(); | ||
96 | } else { | ||
97 | w2(6); l = r1(); w2(4); | ||
98 | w2(6); h = r1(); w2(4); | ||
99 | buf[k] = j44(l,h); | ||
100 | } | ||
101 | w2(4); | ||
102 | } | ||
103 | |||
104 | static void on20_write_block( PIA *pi, char * buf, int count ) | ||
105 | |||
106 | { int k; | ||
107 | |||
108 | op(1); vl(1); op(0); | ||
109 | |||
110 | for (k=0;k<count;k++) { w2(5); w0(buf[k]); w2(7); } | ||
111 | w2(4); | ||
112 | } | ||
113 | |||
114 | static void on20_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
115 | |||
116 | { char *mode_string[2] = {"4-bit","8-bit"}; | ||
117 | |||
118 | printk("%s: on20 %s, OnSpec 90c20 at 0x%x, ", | ||
119 | pi->device,ON20_VERSION,pi->port); | ||
120 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
121 | mode_string[pi->mode],pi->delay); | ||
122 | |||
123 | } | ||
124 | |||
125 | static struct pi_protocol on20 = { | ||
126 | .owner = THIS_MODULE, | ||
127 | .name = "on20", | ||
128 | .max_mode = 2, | ||
129 | .epp_first = 2, | ||
130 | .default_delay = 1, | ||
131 | .max_units = 1, | ||
132 | .write_regr = on20_write_regr, | ||
133 | .read_regr = on20_read_regr, | ||
134 | .write_block = on20_write_block, | ||
135 | .read_block = on20_read_block, | ||
136 | .connect = on20_connect, | ||
137 | .disconnect = on20_disconnect, | ||
138 | .log_adapter = on20_log_adapter, | ||
139 | }; | ||
140 | |||
141 | static int __init on20_init(void) | ||
142 | { | ||
143 | return pi_register(&on20)-1; | ||
144 | } | ||
145 | |||
146 | static void __exit on20_exit(void) | ||
147 | { | ||
148 | pi_unregister(&on20); | ||
149 | } | ||
150 | |||
151 | MODULE_LICENSE("GPL"); | ||
152 | module_init(on20_init) | ||
153 | module_exit(on20_exit) | ||
diff --git a/drivers/block/paride/on26.c b/drivers/block/paride/on26.c new file mode 100644 index 000000000000..9f837d9a3639 --- /dev/null +++ b/drivers/block/paride/on26.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | on26.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | on26.c is a low-level protocol driver for the | ||
6 | OnSpec 90c26 parallel to IDE adapter chip. | ||
7 | |||
8 | */ | ||
9 | |||
10 | /* Changes: | ||
11 | |||
12 | 1.01 GRG 1998.05.06 init_proto, release_proto | ||
13 | 1.02 GRG 1998.09.23 updates for the -E rev chip | ||
14 | 1.03 GRG 1998.12.14 fix for slave drives | ||
15 | 1.04 GRG 1998.12.20 yet another bug fix | ||
16 | |||
17 | */ | ||
18 | |||
19 | #define ON26_VERSION "1.04" | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/wait.h> | ||
27 | #include <asm/io.h> | ||
28 | |||
29 | #include "paride.h" | ||
30 | |||
31 | /* mode codes: 0 nybble reads, 8-bit writes | ||
32 | 1 8-bit reads and writes | ||
33 | 2 8-bit EPP mode | ||
34 | 3 EPP-16 | ||
35 | 4 EPP-32 | ||
36 | */ | ||
37 | |||
38 | #define j44(a,b) (((a>>4)&0x0f)|(b&0xf0)) | ||
39 | |||
40 | #define P1 w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4); | ||
41 | #define P2 w2(5);w2(7);w2(5);w2(4); | ||
42 | |||
43 | /* cont = 0 - access the IDE register file | ||
44 | cont = 1 - access the IDE command set | ||
45 | */ | ||
46 | |||
47 | static int on26_read_regr( PIA *pi, int cont, int regr ) | ||
48 | |||
49 | { int a, b, r; | ||
50 | |||
51 | r = (regr<<2) + 1 + cont; | ||
52 | |||
53 | switch (pi->mode) { | ||
54 | |||
55 | case 0: w0(1); P1; w0(r); P2; w0(0); P1; | ||
56 | w2(6); a = r1(); w2(4); | ||
57 | w2(6); b = r1(); w2(4); | ||
58 | w2(6); w2(4); w2(6); w2(4); | ||
59 | return j44(a,b); | ||
60 | |||
61 | case 1: w0(1); P1; w0(r); P2; w0(0); P1; | ||
62 | w2(0x26); a = r0(); w2(4); w2(0x26); w2(4); | ||
63 | return a; | ||
64 | |||
65 | case 2: | ||
66 | case 3: | ||
67 | case 4: w3(1); w3(1); w2(5); w4(r); w2(4); | ||
68 | w3(0); w3(0); w2(0x24); a = r4(); w2(4); | ||
69 | w2(0x24); r4(); w2(4); | ||
70 | return a; | ||
71 | |||
72 | } | ||
73 | return -1; | ||
74 | } | ||
75 | |||
76 | static void on26_write_regr( PIA *pi, int cont, int regr, int val ) | ||
77 | |||
78 | { int r; | ||
79 | |||
80 | r = (regr<<2) + 1 + cont; | ||
81 | |||
82 | switch (pi->mode) { | ||
83 | |||
84 | case 0: | ||
85 | case 1: w0(1); P1; w0(r); P2; w0(0); P1; | ||
86 | w0(val); P2; w0(val); P2; | ||
87 | break; | ||
88 | |||
89 | case 2: | ||
90 | case 3: | ||
91 | case 4: w3(1); w3(1); w2(5); w4(r); w2(4); | ||
92 | w3(0); w3(0); | ||
93 | w2(5); w4(val); w2(4); | ||
94 | w2(5); w4(val); w2(4); | ||
95 | break; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #define CCP(x) w0(0xfe);w0(0xaa);w0(0x55);w0(0);w0(0xff);\ | ||
100 | w0(0x87);w0(0x78);w0(x);w2(4);w2(5);w2(4);w0(0xff); | ||
101 | |||
102 | static void on26_connect ( PIA *pi ) | ||
103 | |||
104 | { int x; | ||
105 | |||
106 | pi->saved_r0 = r0(); | ||
107 | pi->saved_r2 = r2(); | ||
108 | |||
109 | CCP(0x20); | ||
110 | x = 8; if (pi->mode) x = 9; | ||
111 | |||
112 | w0(2); P1; w0(8); P2; | ||
113 | w0(2); P1; w0(x); P2; | ||
114 | } | ||
115 | |||
116 | static void on26_disconnect ( PIA *pi ) | ||
117 | |||
118 | { if (pi->mode >= 2) { w3(4); w3(4); w3(4); w3(4); } | ||
119 | else { w0(4); P1; w0(4); P1; } | ||
120 | CCP(0x30); | ||
121 | w0(pi->saved_r0); | ||
122 | w2(pi->saved_r2); | ||
123 | } | ||
124 | |||
125 | #define RESET_WAIT 200 | ||
126 | |||
127 | static int on26_test_port( PIA *pi) /* hard reset */ | ||
128 | |||
129 | { int i, m, d, x=0, y=0; | ||
130 | |||
131 | pi->saved_r0 = r0(); | ||
132 | pi->saved_r2 = r2(); | ||
133 | |||
134 | d = pi->delay; | ||
135 | m = pi->mode; | ||
136 | pi->delay = 5; | ||
137 | pi->mode = 0; | ||
138 | |||
139 | w2(0xc); | ||
140 | |||
141 | CCP(0x30); CCP(0); | ||
142 | |||
143 | w0(0xfe);w0(0xaa);w0(0x55);w0(0);w0(0xff); | ||
144 | i = ((r1() & 0xf0) << 4); w0(0x87); | ||
145 | i |= (r1() & 0xf0); w0(0x78); | ||
146 | w0(0x20);w2(4);w2(5); | ||
147 | i |= ((r1() & 0xf0) >> 4); | ||
148 | w2(4);w0(0xff); | ||
149 | |||
150 | if (i == 0xb5f) { | ||
151 | |||
152 | w0(2); P1; w0(0); P2; | ||
153 | w0(3); P1; w0(0); P2; | ||
154 | w0(2); P1; w0(8); P2; udelay(100); | ||
155 | w0(2); P1; w0(0xa); P2; udelay(100); | ||
156 | w0(2); P1; w0(8); P2; udelay(1000); | ||
157 | |||
158 | on26_write_regr(pi,0,6,0xa0); | ||
159 | |||
160 | for (i=0;i<RESET_WAIT;i++) { | ||
161 | on26_write_regr(pi,0,6,0xa0); | ||
162 | x = on26_read_regr(pi,0,7); | ||
163 | on26_write_regr(pi,0,6,0xb0); | ||
164 | y = on26_read_regr(pi,0,7); | ||
165 | if (!((x&0x80)||(y&0x80))) break; | ||
166 | mdelay(100); | ||
167 | } | ||
168 | |||
169 | if (i == RESET_WAIT) | ||
170 | printk("on26: Device reset failed (%x,%x)\n",x,y); | ||
171 | |||
172 | w0(4); P1; w0(4); P1; | ||
173 | } | ||
174 | |||
175 | CCP(0x30); | ||
176 | |||
177 | pi->delay = d; | ||
178 | pi->mode = m; | ||
179 | w0(pi->saved_r0); | ||
180 | w2(pi->saved_r2); | ||
181 | |||
182 | return 5; | ||
183 | } | ||
184 | |||
185 | |||
186 | static void on26_read_block( PIA *pi, char * buf, int count ) | ||
187 | |||
188 | { int k, a, b; | ||
189 | |||
190 | switch (pi->mode) { | ||
191 | |||
192 | case 0: w0(1); P1; w0(1); P2; w0(2); P1; w0(0x18); P2; w0(0); P1; | ||
193 | udelay(10); | ||
194 | for (k=0;k<count;k++) { | ||
195 | w2(6); a = r1(); | ||
196 | w2(4); b = r1(); | ||
197 | buf[k] = j44(a,b); | ||
198 | } | ||
199 | w0(2); P1; w0(8); P2; | ||
200 | break; | ||
201 | |||
202 | case 1: w0(1); P1; w0(1); P2; w0(2); P1; w0(0x19); P2; w0(0); P1; | ||
203 | udelay(10); | ||
204 | for (k=0;k<count/2;k++) { | ||
205 | w2(0x26); buf[2*k] = r0(); | ||
206 | w2(0x24); buf[2*k+1] = r0(); | ||
207 | } | ||
208 | w0(2); P1; w0(9); P2; | ||
209 | break; | ||
210 | |||
211 | case 2: w3(1); w3(1); w2(5); w4(1); w2(4); | ||
212 | w3(0); w3(0); w2(0x24); | ||
213 | udelay(10); | ||
214 | for (k=0;k<count;k++) buf[k] = r4(); | ||
215 | w2(4); | ||
216 | break; | ||
217 | |||
218 | case 3: w3(1); w3(1); w2(5); w4(1); w2(4); | ||
219 | w3(0); w3(0); w2(0x24); | ||
220 | udelay(10); | ||
221 | for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w(); | ||
222 | w2(4); | ||
223 | break; | ||
224 | |||
225 | case 4: w3(1); w3(1); w2(5); w4(1); w2(4); | ||
226 | w3(0); w3(0); w2(0x24); | ||
227 | udelay(10); | ||
228 | for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l(); | ||
229 | w2(4); | ||
230 | break; | ||
231 | |||
232 | } | ||
233 | } | ||
234 | |||
235 | static void on26_write_block( PIA *pi, char * buf, int count ) | ||
236 | |||
237 | { int k; | ||
238 | |||
239 | switch (pi->mode) { | ||
240 | |||
241 | case 0: | ||
242 | case 1: w0(1); P1; w0(1); P2; | ||
243 | w0(2); P1; w0(0x18+pi->mode); P2; w0(0); P1; | ||
244 | udelay(10); | ||
245 | for (k=0;k<count/2;k++) { | ||
246 | w2(5); w0(buf[2*k]); | ||
247 | w2(7); w0(buf[2*k+1]); | ||
248 | } | ||
249 | w2(5); w2(4); | ||
250 | w0(2); P1; w0(8+pi->mode); P2; | ||
251 | break; | ||
252 | |||
253 | case 2: w3(1); w3(1); w2(5); w4(1); w2(4); | ||
254 | w3(0); w3(0); w2(0xc5); | ||
255 | udelay(10); | ||
256 | for (k=0;k<count;k++) w4(buf[k]); | ||
257 | w2(0xc4); | ||
258 | break; | ||
259 | |||
260 | case 3: w3(1); w3(1); w2(5); w4(1); w2(4); | ||
261 | w3(0); w3(0); w2(0xc5); | ||
262 | udelay(10); | ||
263 | for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); | ||
264 | w2(0xc4); | ||
265 | break; | ||
266 | |||
267 | case 4: w3(1); w3(1); w2(5); w4(1); w2(4); | ||
268 | w3(0); w3(0); w2(0xc5); | ||
269 | udelay(10); | ||
270 | for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); | ||
271 | w2(0xc4); | ||
272 | break; | ||
273 | |||
274 | } | ||
275 | |||
276 | } | ||
277 | |||
278 | static void on26_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
279 | |||
280 | { char *mode_string[5] = {"4-bit","8-bit","EPP-8", | ||
281 | "EPP-16","EPP-32"}; | ||
282 | |||
283 | printk("%s: on26 %s, OnSpec 90c26 at 0x%x, ", | ||
284 | pi->device,ON26_VERSION,pi->port); | ||
285 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
286 | mode_string[pi->mode],pi->delay); | ||
287 | |||
288 | } | ||
289 | |||
290 | static struct pi_protocol on26 = { | ||
291 | .owner = THIS_MODULE, | ||
292 | .name = "on26", | ||
293 | .max_mode = 5, | ||
294 | .epp_first = 2, | ||
295 | .default_delay = 1, | ||
296 | .max_units = 1, | ||
297 | .write_regr = on26_write_regr, | ||
298 | .read_regr = on26_read_regr, | ||
299 | .write_block = on26_write_block, | ||
300 | .read_block = on26_read_block, | ||
301 | .connect = on26_connect, | ||
302 | .disconnect = on26_disconnect, | ||
303 | .test_port = on26_test_port, | ||
304 | .log_adapter = on26_log_adapter, | ||
305 | }; | ||
306 | |||
307 | static int __init on26_init(void) | ||
308 | { | ||
309 | return pi_register(&on26)-1; | ||
310 | } | ||
311 | |||
312 | static void __exit on26_exit(void) | ||
313 | { | ||
314 | pi_unregister(&on26); | ||
315 | } | ||
316 | |||
317 | MODULE_LICENSE("GPL"); | ||
318 | module_init(on26_init) | ||
319 | module_exit(on26_exit) | ||
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c new file mode 100644 index 000000000000..1fef136c0e41 --- /dev/null +++ b/drivers/block/paride/paride.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | paride.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is the base module for the family of device drivers | ||
6 | that support parallel port IDE devices. | ||
7 | |||
8 | */ | ||
9 | |||
10 | /* Changes: | ||
11 | |||
12 | 1.01 GRG 1998.05.03 Use spinlocks | ||
13 | 1.02 GRG 1998.05.05 init_proto, release_proto, ktti | ||
14 | 1.03 GRG 1998.08.15 eliminate compiler warning | ||
15 | 1.04 GRG 1998.11.28 added support for FRIQ | ||
16 | 1.05 TMW 2000.06.06 use parport_find_number instead of | ||
17 | parport_enumerate | ||
18 | 1.06 TMW 2001.03.26 more sane parport-or-not resource management | ||
19 | */ | ||
20 | |||
21 | #define PI_VERSION "1.06" | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/config.h> | ||
25 | #include <linux/kmod.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/wait.h> | ||
32 | |||
33 | #ifdef CONFIG_PARPORT_MODULE | ||
34 | #define CONFIG_PARPORT | ||
35 | #endif | ||
36 | |||
37 | #ifdef CONFIG_PARPORT | ||
38 | #include <linux/parport.h> | ||
39 | #endif | ||
40 | |||
41 | #include "paride.h" | ||
42 | |||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | #define MAX_PROTOS 32 | ||
46 | |||
47 | static struct pi_protocol *protocols[MAX_PROTOS]; | ||
48 | |||
49 | static DEFINE_SPINLOCK(pi_spinlock); | ||
50 | |||
51 | void pi_write_regr(PIA * pi, int cont, int regr, int val) | ||
52 | { | ||
53 | pi->proto->write_regr(pi, cont, regr, val); | ||
54 | } | ||
55 | |||
56 | EXPORT_SYMBOL(pi_write_regr); | ||
57 | |||
58 | int pi_read_regr(PIA * pi, int cont, int regr) | ||
59 | { | ||
60 | return pi->proto->read_regr(pi, cont, regr); | ||
61 | } | ||
62 | |||
63 | EXPORT_SYMBOL(pi_read_regr); | ||
64 | |||
65 | void pi_write_block(PIA * pi, char *buf, int count) | ||
66 | { | ||
67 | pi->proto->write_block(pi, buf, count); | ||
68 | } | ||
69 | |||
70 | EXPORT_SYMBOL(pi_write_block); | ||
71 | |||
72 | void pi_read_block(PIA * pi, char *buf, int count) | ||
73 | { | ||
74 | pi->proto->read_block(pi, buf, count); | ||
75 | } | ||
76 | |||
77 | EXPORT_SYMBOL(pi_read_block); | ||
78 | |||
79 | #ifdef CONFIG_PARPORT | ||
80 | |||
81 | static void pi_wake_up(void *p) | ||
82 | { | ||
83 | PIA *pi = (PIA *) p; | ||
84 | unsigned long flags; | ||
85 | void (*cont) (void) = NULL; | ||
86 | |||
87 | spin_lock_irqsave(&pi_spinlock, flags); | ||
88 | |||
89 | if (pi->claim_cont && !parport_claim(pi->pardev)) { | ||
90 | cont = pi->claim_cont; | ||
91 | pi->claim_cont = NULL; | ||
92 | pi->claimed = 1; | ||
93 | } | ||
94 | |||
95 | spin_unlock_irqrestore(&pi_spinlock, flags); | ||
96 | |||
97 | wake_up(&(pi->parq)); | ||
98 | |||
99 | if (cont) | ||
100 | cont(); | ||
101 | } | ||
102 | |||
103 | #endif | ||
104 | |||
105 | int pi_schedule_claimed(PIA * pi, void (*cont) (void)) | ||
106 | { | ||
107 | #ifdef CONFIG_PARPORT | ||
108 | unsigned long flags; | ||
109 | |||
110 | spin_lock_irqsave(&pi_spinlock, flags); | ||
111 | if (pi->pardev && parport_claim(pi->pardev)) { | ||
112 | pi->claim_cont = cont; | ||
113 | spin_unlock_irqrestore(&pi_spinlock, flags); | ||
114 | return 0; | ||
115 | } | ||
116 | pi->claimed = 1; | ||
117 | spin_unlock_irqrestore(&pi_spinlock, flags); | ||
118 | #endif | ||
119 | return 1; | ||
120 | } | ||
121 | EXPORT_SYMBOL(pi_schedule_claimed); | ||
122 | |||
123 | void pi_do_claimed(PIA * pi, void (*cont) (void)) | ||
124 | { | ||
125 | if (pi_schedule_claimed(pi, cont)) | ||
126 | cont(); | ||
127 | } | ||
128 | |||
129 | EXPORT_SYMBOL(pi_do_claimed); | ||
130 | |||
131 | static void pi_claim(PIA * pi) | ||
132 | { | ||
133 | if (pi->claimed) | ||
134 | return; | ||
135 | pi->claimed = 1; | ||
136 | #ifdef CONFIG_PARPORT | ||
137 | if (pi->pardev) | ||
138 | wait_event(pi->parq, | ||
139 | !parport_claim((struct pardevice *) pi->pardev)); | ||
140 | #endif | ||
141 | } | ||
142 | |||
143 | static void pi_unclaim(PIA * pi) | ||
144 | { | ||
145 | pi->claimed = 0; | ||
146 | #ifdef CONFIG_PARPORT | ||
147 | if (pi->pardev) | ||
148 | parport_release((struct pardevice *) (pi->pardev)); | ||
149 | #endif | ||
150 | } | ||
151 | |||
152 | void pi_connect(PIA * pi) | ||
153 | { | ||
154 | pi_claim(pi); | ||
155 | pi->proto->connect(pi); | ||
156 | } | ||
157 | |||
158 | EXPORT_SYMBOL(pi_connect); | ||
159 | |||
160 | void pi_disconnect(PIA * pi) | ||
161 | { | ||
162 | pi->proto->disconnect(pi); | ||
163 | pi_unclaim(pi); | ||
164 | } | ||
165 | |||
166 | EXPORT_SYMBOL(pi_disconnect); | ||
167 | |||
168 | static void pi_unregister_parport(PIA * pi) | ||
169 | { | ||
170 | #ifdef CONFIG_PARPORT | ||
171 | if (pi->pardev) { | ||
172 | parport_unregister_device((struct pardevice *) (pi->pardev)); | ||
173 | pi->pardev = NULL; | ||
174 | } | ||
175 | #endif | ||
176 | } | ||
177 | |||
178 | void pi_release(PIA * pi) | ||
179 | { | ||
180 | pi_unregister_parport(pi); | ||
181 | #ifndef CONFIG_PARPORT | ||
182 | if (pi->reserved) | ||
183 | release_region(pi->port, pi->reserved); | ||
184 | #endif /* !CONFIG_PARPORT */ | ||
185 | if (pi->proto->release_proto) | ||
186 | pi->proto->release_proto(pi); | ||
187 | module_put(pi->proto->owner); | ||
188 | } | ||
189 | |||
190 | EXPORT_SYMBOL(pi_release); | ||
191 | |||
192 | static int default_test_proto(PIA * pi, char *scratch, int verbose) | ||
193 | { | ||
194 | int j, k; | ||
195 | int e[2] = { 0, 0 }; | ||
196 | |||
197 | pi->proto->connect(pi); | ||
198 | |||
199 | for (j = 0; j < 2; j++) { | ||
200 | pi_write_regr(pi, 0, 6, 0xa0 + j * 0x10); | ||
201 | for (k = 0; k < 256; k++) { | ||
202 | pi_write_regr(pi, 0, 2, k ^ 0xaa); | ||
203 | pi_write_regr(pi, 0, 3, k ^ 0x55); | ||
204 | if (pi_read_regr(pi, 0, 2) != (k ^ 0xaa)) | ||
205 | e[j]++; | ||
206 | } | ||
207 | } | ||
208 | pi->proto->disconnect(pi); | ||
209 | |||
210 | if (verbose) | ||
211 | printk("%s: %s: port 0x%x, mode %d, test=(%d,%d)\n", | ||
212 | pi->device, pi->proto->name, pi->port, | ||
213 | pi->mode, e[0], e[1]); | ||
214 | |||
215 | return (e[0] && e[1]); /* not here if both > 0 */ | ||
216 | } | ||
217 | |||
218 | static int pi_test_proto(PIA * pi, char *scratch, int verbose) | ||
219 | { | ||
220 | int res; | ||
221 | |||
222 | pi_claim(pi); | ||
223 | if (pi->proto->test_proto) | ||
224 | res = pi->proto->test_proto(pi, scratch, verbose); | ||
225 | else | ||
226 | res = default_test_proto(pi, scratch, verbose); | ||
227 | pi_unclaim(pi); | ||
228 | |||
229 | return res; | ||
230 | } | ||
231 | |||
232 | int pi_register(PIP * pr) | ||
233 | { | ||
234 | int k; | ||
235 | |||
236 | for (k = 0; k < MAX_PROTOS; k++) | ||
237 | if (protocols[k] && !strcmp(pr->name, protocols[k]->name)) { | ||
238 | printk("paride: %s protocol already registered\n", | ||
239 | pr->name); | ||
240 | return 0; | ||
241 | } | ||
242 | k = 0; | ||
243 | while ((k < MAX_PROTOS) && (protocols[k])) | ||
244 | k++; | ||
245 | if (k == MAX_PROTOS) { | ||
246 | printk("paride: protocol table full\n"); | ||
247 | return 0; | ||
248 | } | ||
249 | protocols[k] = pr; | ||
250 | pr->index = k; | ||
251 | printk("paride: %s registered as protocol %d\n", pr->name, k); | ||
252 | return 1; | ||
253 | } | ||
254 | |||
255 | EXPORT_SYMBOL(pi_register); | ||
256 | |||
257 | void pi_unregister(PIP * pr) | ||
258 | { | ||
259 | if (!pr) | ||
260 | return; | ||
261 | if (protocols[pr->index] != pr) { | ||
262 | printk("paride: %s not registered\n", pr->name); | ||
263 | return; | ||
264 | } | ||
265 | protocols[pr->index] = NULL; | ||
266 | } | ||
267 | |||
268 | EXPORT_SYMBOL(pi_unregister); | ||
269 | |||
270 | static int pi_register_parport(PIA * pi, int verbose) | ||
271 | { | ||
272 | #ifdef CONFIG_PARPORT | ||
273 | |||
274 | struct parport *port; | ||
275 | |||
276 | port = parport_find_base(pi->port); | ||
277 | if (!port) | ||
278 | return 0; | ||
279 | |||
280 | pi->pardev = parport_register_device(port, | ||
281 | pi->device, NULL, | ||
282 | pi_wake_up, NULL, 0, (void *) pi); | ||
283 | parport_put_port(port); | ||
284 | if (!pi->pardev) | ||
285 | return 0; | ||
286 | |||
287 | init_waitqueue_head(&pi->parq); | ||
288 | |||
289 | if (verbose) | ||
290 | printk("%s: 0x%x is %s\n", pi->device, pi->port, port->name); | ||
291 | |||
292 | pi->parname = (char *) port->name; | ||
293 | #endif | ||
294 | |||
295 | return 1; | ||
296 | } | ||
297 | |||
298 | static int pi_probe_mode(PIA * pi, int max, char *scratch, int verbose) | ||
299 | { | ||
300 | int best, range; | ||
301 | |||
302 | if (pi->mode != -1) { | ||
303 | if (pi->mode >= max) | ||
304 | return 0; | ||
305 | range = 3; | ||
306 | if (pi->mode >= pi->proto->epp_first) | ||
307 | range = 8; | ||
308 | if ((range == 8) && (pi->port % 8)) | ||
309 | return 0; | ||
310 | pi->reserved = range; | ||
311 | return (!pi_test_proto(pi, scratch, verbose)); | ||
312 | } | ||
313 | best = -1; | ||
314 | for (pi->mode = 0; pi->mode < max; pi->mode++) { | ||
315 | range = 3; | ||
316 | if (pi->mode >= pi->proto->epp_first) | ||
317 | range = 8; | ||
318 | if ((range == 8) && (pi->port % 8)) | ||
319 | break; | ||
320 | pi->reserved = range; | ||
321 | if (!pi_test_proto(pi, scratch, verbose)) | ||
322 | best = pi->mode; | ||
323 | } | ||
324 | pi->mode = best; | ||
325 | return (best > -1); | ||
326 | } | ||
327 | |||
328 | static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose) | ||
329 | { | ||
330 | int max, s, e; | ||
331 | |||
332 | s = unit; | ||
333 | e = s + 1; | ||
334 | |||
335 | if (s == -1) { | ||
336 | s = 0; | ||
337 | e = pi->proto->max_units; | ||
338 | } | ||
339 | |||
340 | if (!pi_register_parport(pi, verbose)) | ||
341 | return 0; | ||
342 | |||
343 | if (pi->proto->test_port) { | ||
344 | pi_claim(pi); | ||
345 | max = pi->proto->test_port(pi); | ||
346 | pi_unclaim(pi); | ||
347 | } else | ||
348 | max = pi->proto->max_mode; | ||
349 | |||
350 | if (pi->proto->probe_unit) { | ||
351 | pi_claim(pi); | ||
352 | for (pi->unit = s; pi->unit < e; pi->unit++) | ||
353 | if (pi->proto->probe_unit(pi)) { | ||
354 | pi_unclaim(pi); | ||
355 | if (pi_probe_mode(pi, max, scratch, verbose)) | ||
356 | return 1; | ||
357 | pi_unregister_parport(pi); | ||
358 | return 0; | ||
359 | } | ||
360 | pi_unclaim(pi); | ||
361 | pi_unregister_parport(pi); | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | if (!pi_probe_mode(pi, max, scratch, verbose)) { | ||
366 | pi_unregister_parport(pi); | ||
367 | return 0; | ||
368 | } | ||
369 | return 1; | ||
370 | |||
371 | } | ||
372 | |||
373 | int pi_init(PIA * pi, int autoprobe, int port, int mode, | ||
374 | int unit, int protocol, int delay, char *scratch, | ||
375 | int devtype, int verbose, char *device) | ||
376 | { | ||
377 | int p, k, s, e; | ||
378 | int lpts[7] = { 0x3bc, 0x378, 0x278, 0x268, 0x27c, 0x26c, 0 }; | ||
379 | |||
380 | s = protocol; | ||
381 | e = s + 1; | ||
382 | |||
383 | if (!protocols[0]) | ||
384 | request_module("paride_protocol"); | ||
385 | |||
386 | if (autoprobe) { | ||
387 | s = 0; | ||
388 | e = MAX_PROTOS; | ||
389 | } else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) || | ||
390 | (!protocols[s]) || (unit < 0) || | ||
391 | (unit >= protocols[s]->max_units)) { | ||
392 | printk("%s: Invalid parameters\n", device); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | for (p = s; p < e; p++) { | ||
397 | struct pi_protocol *proto = protocols[p]; | ||
398 | if (!proto) | ||
399 | continue; | ||
400 | /* still racy */ | ||
401 | if (!try_module_get(proto->owner)) | ||
402 | continue; | ||
403 | pi->proto = proto; | ||
404 | pi->private = 0; | ||
405 | if (proto->init_proto && proto->init_proto(pi) < 0) { | ||
406 | pi->proto = NULL; | ||
407 | module_put(proto->owner); | ||
408 | continue; | ||
409 | } | ||
410 | if (delay == -1) | ||
411 | pi->delay = pi->proto->default_delay; | ||
412 | else | ||
413 | pi->delay = delay; | ||
414 | pi->devtype = devtype; | ||
415 | pi->device = device; | ||
416 | |||
417 | pi->parname = NULL; | ||
418 | pi->pardev = NULL; | ||
419 | init_waitqueue_head(&pi->parq); | ||
420 | pi->claimed = 0; | ||
421 | pi->claim_cont = NULL; | ||
422 | |||
423 | pi->mode = mode; | ||
424 | if (port != -1) { | ||
425 | pi->port = port; | ||
426 | if (pi_probe_unit(pi, unit, scratch, verbose)) | ||
427 | break; | ||
428 | pi->port = 0; | ||
429 | } else { | ||
430 | k = 0; | ||
431 | while ((pi->port = lpts[k++])) | ||
432 | if (pi_probe_unit | ||
433 | (pi, unit, scratch, verbose)) | ||
434 | break; | ||
435 | if (pi->port) | ||
436 | break; | ||
437 | } | ||
438 | if (pi->proto->release_proto) | ||
439 | pi->proto->release_proto(pi); | ||
440 | module_put(proto->owner); | ||
441 | } | ||
442 | |||
443 | if (!pi->port) { | ||
444 | if (autoprobe) | ||
445 | printk("%s: Autoprobe failed\n", device); | ||
446 | else | ||
447 | printk("%s: Adapter not found\n", device); | ||
448 | return 0; | ||
449 | } | ||
450 | #ifndef CONFIG_PARPORT | ||
451 | if (!request_region(pi->port, pi->reserved, pi->device)) { | ||
452 | printk(KERN_WARNING "paride: Unable to request region 0x%x\n", | ||
453 | pi->port); | ||
454 | return 0; | ||
455 | } | ||
456 | #endif /* !CONFIG_PARPORT */ | ||
457 | |||
458 | if (pi->parname) | ||
459 | printk("%s: Sharing %s at 0x%x\n", pi->device, | ||
460 | pi->parname, pi->port); | ||
461 | |||
462 | pi->proto->log_adapter(pi, scratch, verbose); | ||
463 | |||
464 | return 1; | ||
465 | } | ||
466 | |||
467 | EXPORT_SYMBOL(pi_init); | ||
diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h new file mode 100644 index 000000000000..c6d98ef09e48 --- /dev/null +++ b/drivers/block/paride/paride.h | |||
@@ -0,0 +1,170 @@ | |||
1 | #ifndef __DRIVERS_PARIDE_H__ | ||
2 | #define __DRIVERS_PARIDE_H__ | ||
3 | |||
4 | /* | ||
5 | paride.h (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
6 | Under the terms of the GPL. | ||
7 | |||
8 | This file defines the interface between the high-level parallel | ||
9 | IDE device drivers (pd, pf, pcd, pt) and the adapter chips. | ||
10 | |||
11 | */ | ||
12 | |||
13 | /* Changes: | ||
14 | |||
15 | 1.01 GRG 1998.05.05 init_proto, release_proto | ||
16 | */ | ||
17 | |||
18 | #define PARIDE_H_VERSION "1.01" | ||
19 | |||
20 | /* Some adapters need to know what kind of device they are in | ||
21 | |||
22 | Values for devtype: | ||
23 | */ | ||
24 | |||
25 | #define PI_PD 0 /* IDE disk */ | ||
26 | #define PI_PCD 1 /* ATAPI CDrom */ | ||
27 | #define PI_PF 2 /* ATAPI disk */ | ||
28 | #define PI_PT 3 /* ATAPI tape */ | ||
29 | #define PI_PG 4 /* ATAPI generic */ | ||
30 | |||
31 | /* The paride module contains no state, instead the drivers allocate | ||
32 | a pi_adapter data structure and pass it to paride in every operation. | ||
33 | |||
34 | */ | ||
35 | |||
36 | struct pi_adapter { | ||
37 | |||
38 | struct pi_protocol *proto; /* adapter protocol */ | ||
39 | int port; /* base address of parallel port */ | ||
40 | int mode; /* transfer mode in use */ | ||
41 | int delay; /* adapter delay setting */ | ||
42 | int devtype; /* device type: PI_PD etc. */ | ||
43 | char *device; /* name of driver */ | ||
44 | int unit; /* unit number for chained adapters */ | ||
45 | int saved_r0; /* saved port state */ | ||
46 | int saved_r2; /* saved port state */ | ||
47 | int reserved; /* number of ports reserved */ | ||
48 | unsigned long private; /* for protocol module */ | ||
49 | |||
50 | wait_queue_head_t parq; /* semaphore for parport sharing */ | ||
51 | void *pardev; /* pointer to pardevice */ | ||
52 | char *parname; /* parport name */ | ||
53 | int claimed; /* parport has already been claimed */ | ||
54 | void (*claim_cont)(void); /* continuation for parport wait */ | ||
55 | }; | ||
56 | |||
57 | typedef struct pi_adapter PIA; | ||
58 | |||
59 | /* functions exported by paride to the high level drivers */ | ||
60 | |||
61 | extern int pi_init(PIA *pi, | ||
62 | int autoprobe, /* 1 to autoprobe */ | ||
63 | int port, /* base port address */ | ||
64 | int mode, /* -1 for autoprobe */ | ||
65 | int unit, /* unit number, if supported */ | ||
66 | int protocol, /* protocol to use */ | ||
67 | int delay, /* -1 to use adapter specific default */ | ||
68 | char * scratch, /* address of 512 byte buffer */ | ||
69 | int devtype, /* device type: PI_PD, PI_PCD, etc ... */ | ||
70 | int verbose, /* log verbose data while probing */ | ||
71 | char *device /* name of the driver */ | ||
72 | ); /* returns 0 on failure, 1 on success */ | ||
73 | |||
74 | extern void pi_release(PIA *pi); | ||
75 | |||
76 | /* registers are addressed as (cont,regr) | ||
77 | |||
78 | cont: 0 for command register file, 1 for control register(s) | ||
79 | regr: 0-7 for register number. | ||
80 | |||
81 | */ | ||
82 | |||
83 | extern void pi_write_regr(PIA *pi, int cont, int regr, int val); | ||
84 | |||
85 | extern int pi_read_regr(PIA *pi, int cont, int regr); | ||
86 | |||
87 | extern void pi_write_block(PIA *pi, char * buf, int count); | ||
88 | |||
89 | extern void pi_read_block(PIA *pi, char * buf, int count); | ||
90 | |||
91 | extern void pi_connect(PIA *pi); | ||
92 | |||
93 | extern void pi_disconnect(PIA *pi); | ||
94 | |||
95 | extern void pi_do_claimed(PIA *pi, void (*cont)(void)); | ||
96 | extern int pi_schedule_claimed(PIA *pi, void (*cont)(void)); | ||
97 | |||
98 | /* macros and functions exported to the protocol modules */ | ||
99 | |||
100 | #define delay_p (pi->delay?udelay(pi->delay):(void)0) | ||
101 | #define out_p(offs,byte) outb(byte,pi->port+offs); delay_p; | ||
102 | #define in_p(offs) (delay_p,inb(pi->port+offs)) | ||
103 | |||
104 | #define w0(byte) {out_p(0,byte);} | ||
105 | #define r0() (in_p(0) & 0xff) | ||
106 | #define w1(byte) {out_p(1,byte);} | ||
107 | #define r1() (in_p(1) & 0xff) | ||
108 | #define w2(byte) {out_p(2,byte);} | ||
109 | #define r2() (in_p(2) & 0xff) | ||
110 | #define w3(byte) {out_p(3,byte);} | ||
111 | #define w4(byte) {out_p(4,byte);} | ||
112 | #define r4() (in_p(4) & 0xff) | ||
113 | #define w4w(data) {outw(data,pi->port+4); delay_p;} | ||
114 | #define w4l(data) {outl(data,pi->port+4); delay_p;} | ||
115 | #define r4w() (delay_p,inw(pi->port+4)&0xffff) | ||
116 | #define r4l() (delay_p,inl(pi->port+4)&0xffffffff) | ||
117 | |||
118 | static inline u16 pi_swab16( char *b, int k) | ||
119 | |||
120 | { union { u16 u; char t[2]; } r; | ||
121 | |||
122 | r.t[0]=b[2*k+1]; r.t[1]=b[2*k]; | ||
123 | return r.u; | ||
124 | } | ||
125 | |||
126 | static inline u32 pi_swab32( char *b, int k) | ||
127 | |||
128 | { union { u32 u; char f[4]; } r; | ||
129 | |||
130 | r.f[0]=b[4*k+1]; r.f[1]=b[4*k]; | ||
131 | r.f[2]=b[4*k+3]; r.f[3]=b[4*k+2]; | ||
132 | return r.u; | ||
133 | } | ||
134 | |||
135 | struct pi_protocol { | ||
136 | |||
137 | char name[8]; /* name for this protocol */ | ||
138 | int index; /* index into protocol table */ | ||
139 | |||
140 | int max_mode; /* max mode number */ | ||
141 | int epp_first; /* modes >= this use 8 ports */ | ||
142 | |||
143 | int default_delay; /* delay parameter if not specified */ | ||
144 | int max_units; /* max chained units probed for */ | ||
145 | |||
146 | void (*write_regr)(PIA *,int,int,int); | ||
147 | int (*read_regr)(PIA *,int,int); | ||
148 | void (*write_block)(PIA *,char *,int); | ||
149 | void (*read_block)(PIA *,char *,int); | ||
150 | |||
151 | void (*connect)(PIA *); | ||
152 | void (*disconnect)(PIA *); | ||
153 | |||
154 | int (*test_port)(PIA *); | ||
155 | int (*probe_unit)(PIA *); | ||
156 | int (*test_proto)(PIA *,char *,int); | ||
157 | void (*log_adapter)(PIA *,char *,int); | ||
158 | |||
159 | int (*init_proto)(PIA *); | ||
160 | void (*release_proto)(PIA *); | ||
161 | struct module *owner; | ||
162 | }; | ||
163 | |||
164 | typedef struct pi_protocol PIP; | ||
165 | |||
166 | extern int pi_register( PIP * ); | ||
167 | extern void pi_unregister ( PIP * ); | ||
168 | |||
169 | #endif /* __DRIVERS_PARIDE_H__ */ | ||
170 | /* end of paride.h */ | ||
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c new file mode 100644 index 000000000000..7289f67e9568 --- /dev/null +++ b/drivers/block/paride/pcd.c | |||
@@ -0,0 +1,971 @@ | |||
1 | /* | ||
2 | pcd.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is a high-level driver for parallel port ATAPI CD-ROM | ||
6 | drives based on chips supported by the paride module. | ||
7 | |||
8 | By default, the driver will autoprobe for a single parallel | ||
9 | port ATAPI CD-ROM drive, but if their individual parameters are | ||
10 | specified, the driver can handle up to 4 drives. | ||
11 | |||
12 | The behaviour of the pcd driver can be altered by setting | ||
13 | some parameters from the insmod command line. The following | ||
14 | parameters are adjustable: | ||
15 | |||
16 | drive0 These four arguments can be arrays of | ||
17 | drive1 1-6 integers as follows: | ||
18 | drive2 | ||
19 | drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly> | ||
20 | |||
21 | Where, | ||
22 | |||
23 | <prt> is the base of the parallel port address for | ||
24 | the corresponding drive. (required) | ||
25 | |||
26 | <pro> is the protocol number for the adapter that | ||
27 | supports this drive. These numbers are | ||
28 | logged by 'paride' when the protocol modules | ||
29 | are initialised. (0 if not given) | ||
30 | |||
31 | <uni> for those adapters that support chained | ||
32 | devices, this is the unit selector for the | ||
33 | chain of devices on the given port. It should | ||
34 | be zero for devices that don't support chaining. | ||
35 | (0 if not given) | ||
36 | |||
37 | <mod> this can be -1 to choose the best mode, or one | ||
38 | of the mode numbers supported by the adapter. | ||
39 | (-1 if not given) | ||
40 | |||
41 | <slv> ATAPI CD-ROMs can be jumpered to master or slave. | ||
42 | Set this to 0 to choose the master drive, 1 to | ||
43 | choose the slave, -1 (the default) to choose the | ||
44 | first drive found. | ||
45 | |||
46 | <dly> some parallel ports require the driver to | ||
47 | go more slowly. -1 sets a default value that | ||
48 | should work with the chosen protocol. Otherwise, | ||
49 | set this to a small integer, the larger it is | ||
50 | the slower the port i/o. In some cases, setting | ||
51 | this to zero will speed up the device. (default -1) | ||
52 | |||
53 | major You may use this parameter to overide the | ||
54 | default major number (46) that this driver | ||
55 | will use. Be sure to change the device | ||
56 | name as well. | ||
57 | |||
58 | name This parameter is a character string that | ||
59 | contains the name the kernel will use for this | ||
60 | device (in /proc output, for instance). | ||
61 | (default "pcd") | ||
62 | |||
63 | verbose This parameter controls the amount of logging | ||
64 | that the driver will do. Set it to 0 for | ||
65 | normal operation, 1 to see autoprobe progress | ||
66 | messages, or 2 to see additional debugging | ||
67 | output. (default 0) | ||
68 | |||
69 | nice This parameter controls the driver's use of | ||
70 | idle CPU time, at the expense of some speed. | ||
71 | |||
72 | If this driver is built into the kernel, you can use kernel | ||
73 | the following command line parameters, with the same values | ||
74 | as the corresponding module parameters listed above: | ||
75 | |||
76 | pcd.drive0 | ||
77 | pcd.drive1 | ||
78 | pcd.drive2 | ||
79 | pcd.drive3 | ||
80 | pcd.nice | ||
81 | |||
82 | In addition, you can use the parameter pcd.disable to disable | ||
83 | the driver entirely. | ||
84 | |||
85 | */ | ||
86 | |||
87 | /* Changes: | ||
88 | |||
89 | 1.01 GRG 1998.01.24 Added test unit ready support | ||
90 | 1.02 GRG 1998.05.06 Changes to pcd_completion, ready_wait, | ||
91 | and loosen interpretation of ATAPI | ||
92 | standard for clearing error status. | ||
93 | Use spinlocks. Eliminate sti(). | ||
94 | 1.03 GRG 1998.06.16 Eliminated an Ugh | ||
95 | 1.04 GRG 1998.08.15 Added extra debugging, improvements to | ||
96 | pcd_completion, use HZ in loop timing | ||
97 | 1.05 GRG 1998.08.16 Conformed to "Uniform CD-ROM" standard | ||
98 | 1.06 GRG 1998.08.19 Added audio ioctl support | ||
99 | 1.07 GRG 1998.09.24 Increased reset timeout, added jumbo support | ||
100 | |||
101 | */ | ||
102 | |||
103 | #define PCD_VERSION "1.07" | ||
104 | #define PCD_MAJOR 46 | ||
105 | #define PCD_NAME "pcd" | ||
106 | #define PCD_UNITS 4 | ||
107 | |||
108 | /* Here are things one can override from the insmod command. | ||
109 | Most are autoprobed by paride unless set here. Verbose is off | ||
110 | by default. | ||
111 | |||
112 | */ | ||
113 | |||
114 | static int verbose = 0; | ||
115 | static int major = PCD_MAJOR; | ||
116 | static char *name = PCD_NAME; | ||
117 | static int nice = 0; | ||
118 | static int disable = 0; | ||
119 | |||
120 | static int drive0[6] = { 0, 0, 0, -1, -1, -1 }; | ||
121 | static int drive1[6] = { 0, 0, 0, -1, -1, -1 }; | ||
122 | static int drive2[6] = { 0, 0, 0, -1, -1, -1 }; | ||
123 | static int drive3[6] = { 0, 0, 0, -1, -1, -1 }; | ||
124 | |||
125 | static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; | ||
126 | static int pcd_drive_count; | ||
127 | |||
128 | enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; | ||
129 | |||
130 | /* end of parameters */ | ||
131 | |||
132 | #include <linux/module.h> | ||
133 | #include <linux/init.h> | ||
134 | #include <linux/errno.h> | ||
135 | #include <linux/fs.h> | ||
136 | #include <linux/kernel.h> | ||
137 | #include <linux/delay.h> | ||
138 | #include <linux/cdrom.h> | ||
139 | #include <linux/spinlock.h> | ||
140 | #include <linux/blkdev.h> | ||
141 | #include <asm/uaccess.h> | ||
142 | |||
143 | static spinlock_t pcd_lock; | ||
144 | |||
145 | module_param(verbose, bool, 0644); | ||
146 | module_param(major, int, 0); | ||
147 | module_param(name, charp, 0); | ||
148 | module_param(nice, int, 0); | ||
149 | module_param_array(drive0, int, NULL, 0); | ||
150 | module_param_array(drive1, int, NULL, 0); | ||
151 | module_param_array(drive2, int, NULL, 0); | ||
152 | module_param_array(drive3, int, NULL, 0); | ||
153 | |||
154 | #include "paride.h" | ||
155 | #include "pseudo.h" | ||
156 | |||
157 | #define PCD_RETRIES 5 | ||
158 | #define PCD_TMO 800 /* timeout in jiffies */ | ||
159 | #define PCD_DELAY 50 /* spin delay in uS */ | ||
160 | #define PCD_READY_TMO 20 /* in seconds */ | ||
161 | #define PCD_RESET_TMO 100 /* in tenths of a second */ | ||
162 | |||
163 | #define PCD_SPIN (1000000*PCD_TMO)/(HZ*PCD_DELAY) | ||
164 | |||
165 | #define IDE_ERR 0x01 | ||
166 | #define IDE_DRQ 0x08 | ||
167 | #define IDE_READY 0x40 | ||
168 | #define IDE_BUSY 0x80 | ||
169 | |||
170 | static int pcd_open(struct cdrom_device_info *cdi, int purpose); | ||
171 | static void pcd_release(struct cdrom_device_info *cdi); | ||
172 | static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr); | ||
173 | static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr); | ||
174 | static int pcd_tray_move(struct cdrom_device_info *cdi, int position); | ||
175 | static int pcd_lock_door(struct cdrom_device_info *cdi, int lock); | ||
176 | static int pcd_drive_reset(struct cdrom_device_info *cdi); | ||
177 | static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn); | ||
178 | static int pcd_audio_ioctl(struct cdrom_device_info *cdi, | ||
179 | unsigned int cmd, void *arg); | ||
180 | static int pcd_packet(struct cdrom_device_info *cdi, | ||
181 | struct packet_command *cgc); | ||
182 | |||
183 | static int pcd_detect(void); | ||
184 | static void pcd_probe_capabilities(void); | ||
185 | static void do_pcd_read_drq(void); | ||
186 | static void do_pcd_request(request_queue_t * q); | ||
187 | static void do_pcd_read(void); | ||
188 | |||
189 | struct pcd_unit { | ||
190 | struct pi_adapter pia; /* interface to paride layer */ | ||
191 | struct pi_adapter *pi; | ||
192 | int drive; /* master/slave */ | ||
193 | int last_sense; /* result of last request sense */ | ||
194 | int changed; /* media change seen */ | ||
195 | int present; /* does this unit exist ? */ | ||
196 | char *name; /* pcd0, pcd1, etc */ | ||
197 | struct cdrom_device_info info; /* uniform cdrom interface */ | ||
198 | struct gendisk *disk; | ||
199 | }; | ||
200 | |||
201 | static struct pcd_unit pcd[PCD_UNITS]; | ||
202 | |||
203 | static char pcd_scratch[64]; | ||
204 | static char pcd_buffer[2048]; /* raw block buffer */ | ||
205 | static int pcd_bufblk = -1; /* block in buffer, in CD units, | ||
206 | -1 for nothing there. See also | ||
207 | pd_unit. | ||
208 | */ | ||
209 | |||
210 | /* the variables below are used mainly in the I/O request engine, which | ||
211 | processes only one request at a time. | ||
212 | */ | ||
213 | |||
214 | static struct pcd_unit *pcd_current; /* current request's drive */ | ||
215 | static struct request *pcd_req; | ||
216 | static int pcd_retries; /* retries on current request */ | ||
217 | static int pcd_busy; /* request being processed ? */ | ||
218 | static int pcd_sector; /* address of next requested sector */ | ||
219 | static int pcd_count; /* number of blocks still to do */ | ||
220 | static char *pcd_buf; /* buffer for request in progress */ | ||
221 | |||
222 | static int pcd_warned; /* Have we logged a phase warning ? */ | ||
223 | |||
224 | /* kernel glue structures */ | ||
225 | |||
226 | static int pcd_block_open(struct inode *inode, struct file *file) | ||
227 | { | ||
228 | struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; | ||
229 | return cdrom_open(&cd->info, inode, file); | ||
230 | } | ||
231 | |||
232 | static int pcd_block_release(struct inode *inode, struct file *file) | ||
233 | { | ||
234 | struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; | ||
235 | return cdrom_release(&cd->info, file); | ||
236 | } | ||
237 | |||
238 | static int pcd_block_ioctl(struct inode *inode, struct file *file, | ||
239 | unsigned cmd, unsigned long arg) | ||
240 | { | ||
241 | struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data; | ||
242 | return cdrom_ioctl(file, &cd->info, inode, cmd, arg); | ||
243 | } | ||
244 | |||
245 | static int pcd_block_media_changed(struct gendisk *disk) | ||
246 | { | ||
247 | struct pcd_unit *cd = disk->private_data; | ||
248 | return cdrom_media_changed(&cd->info); | ||
249 | } | ||
250 | |||
251 | static struct block_device_operations pcd_bdops = { | ||
252 | .owner = THIS_MODULE, | ||
253 | .open = pcd_block_open, | ||
254 | .release = pcd_block_release, | ||
255 | .ioctl = pcd_block_ioctl, | ||
256 | .media_changed = pcd_block_media_changed, | ||
257 | }; | ||
258 | |||
259 | static struct cdrom_device_ops pcd_dops = { | ||
260 | .open = pcd_open, | ||
261 | .release = pcd_release, | ||
262 | .drive_status = pcd_drive_status, | ||
263 | .media_changed = pcd_media_changed, | ||
264 | .tray_move = pcd_tray_move, | ||
265 | .lock_door = pcd_lock_door, | ||
266 | .get_mcn = pcd_get_mcn, | ||
267 | .reset = pcd_drive_reset, | ||
268 | .audio_ioctl = pcd_audio_ioctl, | ||
269 | .generic_packet = pcd_packet, | ||
270 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | | ||
271 | CDC_MCN | CDC_MEDIA_CHANGED | CDC_RESET | | ||
272 | CDC_PLAY_AUDIO | CDC_GENERIC_PACKET | CDC_CD_R | | ||
273 | CDC_CD_RW, | ||
274 | }; | ||
275 | |||
276 | static void pcd_init_units(void) | ||
277 | { | ||
278 | struct pcd_unit *cd; | ||
279 | int unit; | ||
280 | |||
281 | pcd_drive_count = 0; | ||
282 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { | ||
283 | struct gendisk *disk = alloc_disk(1); | ||
284 | if (!disk) | ||
285 | continue; | ||
286 | cd->disk = disk; | ||
287 | cd->pi = &cd->pia; | ||
288 | cd->present = 0; | ||
289 | cd->last_sense = 0; | ||
290 | cd->changed = 1; | ||
291 | cd->drive = (*drives[unit])[D_SLV]; | ||
292 | if ((*drives[unit])[D_PRT]) | ||
293 | pcd_drive_count++; | ||
294 | |||
295 | cd->name = &cd->info.name[0]; | ||
296 | snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit); | ||
297 | cd->info.ops = &pcd_dops; | ||
298 | cd->info.handle = cd; | ||
299 | cd->info.speed = 0; | ||
300 | cd->info.capacity = 1; | ||
301 | cd->info.mask = 0; | ||
302 | disk->major = major; | ||
303 | disk->first_minor = unit; | ||
304 | strcpy(disk->disk_name, cd->name); /* umm... */ | ||
305 | disk->fops = &pcd_bdops; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | static int pcd_open(struct cdrom_device_info *cdi, int purpose) | ||
310 | { | ||
311 | struct pcd_unit *cd = cdi->handle; | ||
312 | if (!cd->present) | ||
313 | return -ENODEV; | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static void pcd_release(struct cdrom_device_info *cdi) | ||
318 | { | ||
319 | } | ||
320 | |||
321 | static inline int status_reg(struct pcd_unit *cd) | ||
322 | { | ||
323 | return pi_read_regr(cd->pi, 1, 6); | ||
324 | } | ||
325 | |||
326 | static inline int read_reg(struct pcd_unit *cd, int reg) | ||
327 | { | ||
328 | return pi_read_regr(cd->pi, 0, reg); | ||
329 | } | ||
330 | |||
331 | static inline void write_reg(struct pcd_unit *cd, int reg, int val) | ||
332 | { | ||
333 | pi_write_regr(cd->pi, 0, reg, val); | ||
334 | } | ||
335 | |||
336 | static int pcd_wait(struct pcd_unit *cd, int go, int stop, char *fun, char *msg) | ||
337 | { | ||
338 | int j, r, e, s, p; | ||
339 | |||
340 | j = 0; | ||
341 | while ((((r = status_reg(cd)) & go) || (stop && (!(r & stop)))) | ||
342 | && (j++ < PCD_SPIN)) | ||
343 | udelay(PCD_DELAY); | ||
344 | |||
345 | if ((r & (IDE_ERR & stop)) || (j >= PCD_SPIN)) { | ||
346 | s = read_reg(cd, 7); | ||
347 | e = read_reg(cd, 1); | ||
348 | p = read_reg(cd, 2); | ||
349 | if (j >= PCD_SPIN) | ||
350 | e |= 0x100; | ||
351 | if (fun) | ||
352 | printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x" | ||
353 | " loop=%d phase=%d\n", | ||
354 | cd->name, fun, msg, r, s, e, j, p); | ||
355 | return (s << 8) + r; | ||
356 | } | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int pcd_command(struct pcd_unit *cd, char *cmd, int dlen, char *fun) | ||
361 | { | ||
362 | pi_connect(cd->pi); | ||
363 | |||
364 | write_reg(cd, 6, 0xa0 + 0x10 * cd->drive); | ||
365 | |||
366 | if (pcd_wait(cd, IDE_BUSY | IDE_DRQ, 0, fun, "before command")) { | ||
367 | pi_disconnect(cd->pi); | ||
368 | return -1; | ||
369 | } | ||
370 | |||
371 | write_reg(cd, 4, dlen % 256); | ||
372 | write_reg(cd, 5, dlen / 256); | ||
373 | write_reg(cd, 7, 0xa0); /* ATAPI packet command */ | ||
374 | |||
375 | if (pcd_wait(cd, IDE_BUSY, IDE_DRQ, fun, "command DRQ")) { | ||
376 | pi_disconnect(cd->pi); | ||
377 | return -1; | ||
378 | } | ||
379 | |||
380 | if (read_reg(cd, 2) != 1) { | ||
381 | printk("%s: %s: command phase error\n", cd->name, fun); | ||
382 | pi_disconnect(cd->pi); | ||
383 | return -1; | ||
384 | } | ||
385 | |||
386 | pi_write_block(cd->pi, cmd, 12); | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun) | ||
392 | { | ||
393 | int r, d, p, n, k, j; | ||
394 | |||
395 | r = -1; | ||
396 | k = 0; | ||
397 | j = 0; | ||
398 | |||
399 | if (!pcd_wait(cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR, | ||
400 | fun, "completion")) { | ||
401 | r = 0; | ||
402 | while (read_reg(cd, 7) & IDE_DRQ) { | ||
403 | d = read_reg(cd, 4) + 256 * read_reg(cd, 5); | ||
404 | n = (d + 3) & 0xfffc; | ||
405 | p = read_reg(cd, 2) & 3; | ||
406 | |||
407 | if ((p == 2) && (n > 0) && (j == 0)) { | ||
408 | pi_read_block(cd->pi, buf, n); | ||
409 | if (verbose > 1) | ||
410 | printk("%s: %s: Read %d bytes\n", | ||
411 | cd->name, fun, n); | ||
412 | r = 0; | ||
413 | j++; | ||
414 | } else { | ||
415 | if (verbose > 1) | ||
416 | printk | ||
417 | ("%s: %s: Unexpected phase %d, d=%d, k=%d\n", | ||
418 | cd->name, fun, p, d, k); | ||
419 | if ((verbose < 2) && !pcd_warned) { | ||
420 | pcd_warned = 1; | ||
421 | printk | ||
422 | ("%s: WARNING: ATAPI phase errors\n", | ||
423 | cd->name); | ||
424 | } | ||
425 | mdelay(1); | ||
426 | } | ||
427 | if (k++ > PCD_TMO) { | ||
428 | printk("%s: Stuck DRQ\n", cd->name); | ||
429 | break; | ||
430 | } | ||
431 | if (pcd_wait | ||
432 | (cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR, fun, | ||
433 | "completion")) { | ||
434 | r = -1; | ||
435 | break; | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | |||
440 | pi_disconnect(cd->pi); | ||
441 | |||
442 | return r; | ||
443 | } | ||
444 | |||
445 | static void pcd_req_sense(struct pcd_unit *cd, char *fun) | ||
446 | { | ||
447 | char rs_cmd[12] = { 0x03, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 }; | ||
448 | char buf[16]; | ||
449 | int r, c; | ||
450 | |||
451 | r = pcd_command(cd, rs_cmd, 16, "Request sense"); | ||
452 | mdelay(1); | ||
453 | if (!r) | ||
454 | pcd_completion(cd, buf, "Request sense"); | ||
455 | |||
456 | cd->last_sense = -1; | ||
457 | c = 2; | ||
458 | if (!r) { | ||
459 | if (fun) | ||
460 | printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n", | ||
461 | cd->name, fun, buf[2] & 0xf, buf[12], buf[13]); | ||
462 | c = buf[2] & 0xf; | ||
463 | cd->last_sense = | ||
464 | c | ((buf[12] & 0xff) << 8) | ((buf[13] & 0xff) << 16); | ||
465 | } | ||
466 | if ((c == 2) || (c == 6)) | ||
467 | cd->changed = 1; | ||
468 | } | ||
469 | |||
470 | static int pcd_atapi(struct pcd_unit *cd, char *cmd, int dlen, char *buf, char *fun) | ||
471 | { | ||
472 | int r; | ||
473 | |||
474 | r = pcd_command(cd, cmd, dlen, fun); | ||
475 | mdelay(1); | ||
476 | if (!r) | ||
477 | r = pcd_completion(cd, buf, fun); | ||
478 | if (r) | ||
479 | pcd_req_sense(cd, fun); | ||
480 | |||
481 | return r; | ||
482 | } | ||
483 | |||
484 | static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc) | ||
485 | { | ||
486 | return pcd_atapi(cdi->handle, cgc->cmd, cgc->buflen, cgc->buffer, | ||
487 | "generic packet"); | ||
488 | } | ||
489 | |||
490 | #define DBMSG(msg) ((verbose>1)?(msg):NULL) | ||
491 | |||
492 | static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr) | ||
493 | { | ||
494 | struct pcd_unit *cd = cdi->handle; | ||
495 | int res = cd->changed; | ||
496 | if (res) | ||
497 | cd->changed = 0; | ||
498 | return res; | ||
499 | } | ||
500 | |||
501 | static int pcd_lock_door(struct cdrom_device_info *cdi, int lock) | ||
502 | { | ||
503 | char un_cmd[12] = { 0x1e, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0 }; | ||
504 | |||
505 | return pcd_atapi(cdi->handle, un_cmd, 0, pcd_scratch, | ||
506 | lock ? "lock door" : "unlock door"); | ||
507 | } | ||
508 | |||
509 | static int pcd_tray_move(struct cdrom_device_info *cdi, int position) | ||
510 | { | ||
511 | char ej_cmd[12] = { 0x1b, 0, 0, 0, 3 - position, 0, 0, 0, 0, 0, 0, 0 }; | ||
512 | |||
513 | return pcd_atapi(cdi->handle, ej_cmd, 0, pcd_scratch, | ||
514 | position ? "eject" : "close tray"); | ||
515 | } | ||
516 | |||
517 | static void pcd_sleep(int cs) | ||
518 | { | ||
519 | current->state = TASK_INTERRUPTIBLE; | ||
520 | schedule_timeout(cs); | ||
521 | } | ||
522 | |||
523 | static int pcd_reset(struct pcd_unit *cd) | ||
524 | { | ||
525 | int i, k, flg; | ||
526 | int expect[5] = { 1, 1, 1, 0x14, 0xeb }; | ||
527 | |||
528 | pi_connect(cd->pi); | ||
529 | write_reg(cd, 6, 0xa0 + 0x10 * cd->drive); | ||
530 | write_reg(cd, 7, 8); | ||
531 | |||
532 | pcd_sleep(20 * HZ / 1000); /* delay a bit */ | ||
533 | |||
534 | k = 0; | ||
535 | while ((k++ < PCD_RESET_TMO) && (status_reg(cd) & IDE_BUSY)) | ||
536 | pcd_sleep(HZ / 10); | ||
537 | |||
538 | flg = 1; | ||
539 | for (i = 0; i < 5; i++) | ||
540 | flg &= (read_reg(cd, i + 1) == expect[i]); | ||
541 | |||
542 | if (verbose) { | ||
543 | printk("%s: Reset (%d) signature = ", cd->name, k); | ||
544 | for (i = 0; i < 5; i++) | ||
545 | printk("%3x", read_reg(cd, i + 1)); | ||
546 | if (!flg) | ||
547 | printk(" (incorrect)"); | ||
548 | printk("\n"); | ||
549 | } | ||
550 | |||
551 | pi_disconnect(cd->pi); | ||
552 | return flg - 1; | ||
553 | } | ||
554 | |||
555 | static int pcd_drive_reset(struct cdrom_device_info *cdi) | ||
556 | { | ||
557 | return pcd_reset(cdi->handle); | ||
558 | } | ||
559 | |||
560 | static int pcd_ready_wait(struct pcd_unit *cd, int tmo) | ||
561 | { | ||
562 | char tr_cmd[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
563 | int k, p; | ||
564 | |||
565 | k = 0; | ||
566 | while (k < tmo) { | ||
567 | cd->last_sense = 0; | ||
568 | pcd_atapi(cd, tr_cmd, 0, NULL, DBMSG("test unit ready")); | ||
569 | p = cd->last_sense; | ||
570 | if (!p) | ||
571 | return 0; | ||
572 | if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6))) | ||
573 | return p; | ||
574 | k++; | ||
575 | pcd_sleep(HZ); | ||
576 | } | ||
577 | return 0x000020; /* timeout */ | ||
578 | } | ||
579 | |||
580 | static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr) | ||
581 | { | ||
582 | char rc_cmd[12] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
583 | struct pcd_unit *cd = cdi->handle; | ||
584 | |||
585 | if (pcd_ready_wait(cd, PCD_READY_TMO)) | ||
586 | return CDS_DRIVE_NOT_READY; | ||
587 | if (pcd_atapi(cd, rc_cmd, 8, pcd_scratch, DBMSG("check media"))) | ||
588 | return CDS_NO_DISC; | ||
589 | return CDS_DISC_OK; | ||
590 | } | ||
591 | |||
592 | static int pcd_identify(struct pcd_unit *cd, char *id) | ||
593 | { | ||
594 | int k, s; | ||
595 | char id_cmd[12] = { 0x12, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; | ||
596 | |||
597 | pcd_bufblk = -1; | ||
598 | |||
599 | s = pcd_atapi(cd, id_cmd, 36, pcd_buffer, "identify"); | ||
600 | |||
601 | if (s) | ||
602 | return -1; | ||
603 | if ((pcd_buffer[0] & 0x1f) != 5) { | ||
604 | if (verbose) | ||
605 | printk("%s: %s is not a CD-ROM\n", | ||
606 | cd->name, cd->drive ? "Slave" : "Master"); | ||
607 | return -1; | ||
608 | } | ||
609 | memcpy(id, pcd_buffer + 16, 16); | ||
610 | id[16] = 0; | ||
611 | k = 16; | ||
612 | while ((k >= 0) && (id[k] <= 0x20)) { | ||
613 | id[k] = 0; | ||
614 | k--; | ||
615 | } | ||
616 | |||
617 | printk("%s: %s: %s\n", cd->name, cd->drive ? "Slave" : "Master", id); | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | /* | ||
623 | * returns 0, with id set if drive is detected | ||
624 | * -1, if drive detection failed | ||
625 | */ | ||
626 | static int pcd_probe(struct pcd_unit *cd, int ms, char *id) | ||
627 | { | ||
628 | if (ms == -1) { | ||
629 | for (cd->drive = 0; cd->drive <= 1; cd->drive++) | ||
630 | if (!pcd_reset(cd) && !pcd_identify(cd, id)) | ||
631 | return 0; | ||
632 | } else { | ||
633 | cd->drive = ms; | ||
634 | if (!pcd_reset(cd) && !pcd_identify(cd, id)) | ||
635 | return 0; | ||
636 | } | ||
637 | return -1; | ||
638 | } | ||
639 | |||
640 | static void pcd_probe_capabilities(void) | ||
641 | { | ||
642 | int unit, r; | ||
643 | char buffer[32]; | ||
644 | char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 }; | ||
645 | struct pcd_unit *cd; | ||
646 | |||
647 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { | ||
648 | if (!cd->present) | ||
649 | continue; | ||
650 | r = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities"); | ||
651 | if (r) | ||
652 | continue; | ||
653 | /* we should now have the cap page */ | ||
654 | if ((buffer[11] & 1) == 0) | ||
655 | cd->info.mask |= CDC_CD_R; | ||
656 | if ((buffer[11] & 2) == 0) | ||
657 | cd->info.mask |= CDC_CD_RW; | ||
658 | if ((buffer[12] & 1) == 0) | ||
659 | cd->info.mask |= CDC_PLAY_AUDIO; | ||
660 | if ((buffer[14] & 1) == 0) | ||
661 | cd->info.mask |= CDC_LOCK; | ||
662 | if ((buffer[14] & 8) == 0) | ||
663 | cd->info.mask |= CDC_OPEN_TRAY; | ||
664 | if ((buffer[14] >> 6) == 0) | ||
665 | cd->info.mask |= CDC_CLOSE_TRAY; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | static int pcd_detect(void) | ||
670 | { | ||
671 | char id[18]; | ||
672 | int k, unit; | ||
673 | struct pcd_unit *cd; | ||
674 | |||
675 | printk("%s: %s version %s, major %d, nice %d\n", | ||
676 | name, name, PCD_VERSION, major, nice); | ||
677 | |||
678 | k = 0; | ||
679 | if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ | ||
680 | cd = pcd; | ||
681 | if (pi_init(cd->pi, 1, -1, -1, -1, -1, -1, pcd_buffer, | ||
682 | PI_PCD, verbose, cd->name)) { | ||
683 | if (!pcd_probe(cd, -1, id) && cd->disk) { | ||
684 | cd->present = 1; | ||
685 | k++; | ||
686 | } else | ||
687 | pi_release(cd->pi); | ||
688 | } | ||
689 | } else { | ||
690 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { | ||
691 | int *conf = *drives[unit]; | ||
692 | if (!conf[D_PRT]) | ||
693 | continue; | ||
694 | if (!pi_init(cd->pi, 0, conf[D_PRT], conf[D_MOD], | ||
695 | conf[D_UNI], conf[D_PRO], conf[D_DLY], | ||
696 | pcd_buffer, PI_PCD, verbose, cd->name)) | ||
697 | continue; | ||
698 | if (!pcd_probe(cd, conf[D_SLV], id) && cd->disk) { | ||
699 | cd->present = 1; | ||
700 | k++; | ||
701 | } else | ||
702 | pi_release(cd->pi); | ||
703 | } | ||
704 | } | ||
705 | if (k) | ||
706 | return 0; | ||
707 | |||
708 | printk("%s: No CD-ROM drive found\n", name); | ||
709 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) | ||
710 | put_disk(cd->disk); | ||
711 | return -1; | ||
712 | } | ||
713 | |||
714 | /* I/O request processing */ | ||
715 | static struct request_queue *pcd_queue; | ||
716 | |||
717 | static void do_pcd_request(request_queue_t * q) | ||
718 | { | ||
719 | if (pcd_busy) | ||
720 | return; | ||
721 | while (1) { | ||
722 | pcd_req = elv_next_request(q); | ||
723 | if (!pcd_req) | ||
724 | return; | ||
725 | |||
726 | if (rq_data_dir(pcd_req) == READ) { | ||
727 | struct pcd_unit *cd = pcd_req->rq_disk->private_data; | ||
728 | if (cd != pcd_current) | ||
729 | pcd_bufblk = -1; | ||
730 | pcd_current = cd; | ||
731 | pcd_sector = pcd_req->sector; | ||
732 | pcd_count = pcd_req->current_nr_sectors; | ||
733 | pcd_buf = pcd_req->buffer; | ||
734 | pcd_busy = 1; | ||
735 | ps_set_intr(do_pcd_read, NULL, 0, nice); | ||
736 | return; | ||
737 | } else | ||
738 | end_request(pcd_req, 0); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | static inline void next_request(int success) | ||
743 | { | ||
744 | unsigned long saved_flags; | ||
745 | |||
746 | spin_lock_irqsave(&pcd_lock, saved_flags); | ||
747 | end_request(pcd_req, success); | ||
748 | pcd_busy = 0; | ||
749 | do_pcd_request(pcd_queue); | ||
750 | spin_unlock_irqrestore(&pcd_lock, saved_flags); | ||
751 | } | ||
752 | |||
753 | static int pcd_ready(void) | ||
754 | { | ||
755 | return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ)); | ||
756 | } | ||
757 | |||
758 | static void pcd_transfer(void) | ||
759 | { | ||
760 | |||
761 | while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) { | ||
762 | int o = (pcd_sector % 4) * 512; | ||
763 | memcpy(pcd_buf, pcd_buffer + o, 512); | ||
764 | pcd_count--; | ||
765 | pcd_buf += 512; | ||
766 | pcd_sector++; | ||
767 | } | ||
768 | } | ||
769 | |||
770 | static void pcd_start(void) | ||
771 | { | ||
772 | int b, i; | ||
773 | char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }; | ||
774 | |||
775 | pcd_bufblk = pcd_sector / 4; | ||
776 | b = pcd_bufblk; | ||
777 | for (i = 0; i < 4; i++) { | ||
778 | rd_cmd[5 - i] = b & 0xff; | ||
779 | b = b >> 8; | ||
780 | } | ||
781 | |||
782 | if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) { | ||
783 | pcd_bufblk = -1; | ||
784 | next_request(0); | ||
785 | return; | ||
786 | } | ||
787 | |||
788 | mdelay(1); | ||
789 | |||
790 | ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice); | ||
791 | } | ||
792 | |||
793 | static void do_pcd_read(void) | ||
794 | { | ||
795 | pcd_busy = 1; | ||
796 | pcd_retries = 0; | ||
797 | pcd_transfer(); | ||
798 | if (!pcd_count) { | ||
799 | next_request(1); | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | pi_do_claimed(pcd_current->pi, pcd_start); | ||
804 | } | ||
805 | |||
806 | static void do_pcd_read_drq(void) | ||
807 | { | ||
808 | unsigned long saved_flags; | ||
809 | |||
810 | if (pcd_completion(pcd_current, pcd_buffer, "read block")) { | ||
811 | if (pcd_retries < PCD_RETRIES) { | ||
812 | mdelay(1); | ||
813 | pcd_retries++; | ||
814 | pi_do_claimed(pcd_current->pi, pcd_start); | ||
815 | return; | ||
816 | } | ||
817 | pcd_bufblk = -1; | ||
818 | next_request(0); | ||
819 | return; | ||
820 | } | ||
821 | |||
822 | do_pcd_read(); | ||
823 | spin_lock_irqsave(&pcd_lock, saved_flags); | ||
824 | do_pcd_request(pcd_queue); | ||
825 | spin_unlock_irqrestore(&pcd_lock, saved_flags); | ||
826 | } | ||
827 | |||
828 | /* the audio_ioctl stuff is adapted from sr_ioctl.c */ | ||
829 | |||
830 | static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) | ||
831 | { | ||
832 | struct pcd_unit *cd = cdi->handle; | ||
833 | |||
834 | switch (cmd) { | ||
835 | |||
836 | case CDROMREADTOCHDR: | ||
837 | |||
838 | { | ||
839 | char cmd[12] = | ||
840 | { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12, | ||
841 | 0, 0, 0 }; | ||
842 | struct cdrom_tochdr *tochdr = | ||
843 | (struct cdrom_tochdr *) arg; | ||
844 | char buffer[32]; | ||
845 | int r; | ||
846 | |||
847 | r = pcd_atapi(cd, cmd, 12, buffer, "read toc header"); | ||
848 | |||
849 | tochdr->cdth_trk0 = buffer[2]; | ||
850 | tochdr->cdth_trk1 = buffer[3]; | ||
851 | |||
852 | return r ? -EIO : 0; | ||
853 | } | ||
854 | |||
855 | case CDROMREADTOCENTRY: | ||
856 | |||
857 | { | ||
858 | char cmd[12] = | ||
859 | { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12, | ||
860 | 0, 0, 0 }; | ||
861 | |||
862 | struct cdrom_tocentry *tocentry = | ||
863 | (struct cdrom_tocentry *) arg; | ||
864 | unsigned char buffer[32]; | ||
865 | int r; | ||
866 | |||
867 | cmd[1] = | ||
868 | (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); | ||
869 | cmd[6] = tocentry->cdte_track; | ||
870 | |||
871 | r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry"); | ||
872 | |||
873 | tocentry->cdte_ctrl = buffer[5] & 0xf; | ||
874 | tocentry->cdte_adr = buffer[5] >> 4; | ||
875 | tocentry->cdte_datamode = | ||
876 | (tocentry->cdte_ctrl & 0x04) ? 1 : 0; | ||
877 | if (tocentry->cdte_format == CDROM_MSF) { | ||
878 | tocentry->cdte_addr.msf.minute = buffer[9]; | ||
879 | tocentry->cdte_addr.msf.second = buffer[10]; | ||
880 | tocentry->cdte_addr.msf.frame = buffer[11]; | ||
881 | } else | ||
882 | tocentry->cdte_addr.lba = | ||
883 | (((((buffer[8] << 8) + buffer[9]) << 8) | ||
884 | + buffer[10]) << 8) + buffer[11]; | ||
885 | |||
886 | return r ? -EIO : 0; | ||
887 | } | ||
888 | |||
889 | default: | ||
890 | |||
891 | return -ENOSYS; | ||
892 | } | ||
893 | } | ||
894 | |||
895 | static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) | ||
896 | { | ||
897 | char cmd[12] = | ||
898 | { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 }; | ||
899 | char buffer[32]; | ||
900 | |||
901 | if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn")) | ||
902 | return -EIO; | ||
903 | |||
904 | memcpy(mcn->medium_catalog_number, buffer + 9, 13); | ||
905 | mcn->medium_catalog_number[13] = 0; | ||
906 | |||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static int __init pcd_init(void) | ||
911 | { | ||
912 | struct pcd_unit *cd; | ||
913 | int unit; | ||
914 | |||
915 | if (disable) | ||
916 | return -1; | ||
917 | |||
918 | pcd_init_units(); | ||
919 | |||
920 | if (pcd_detect()) | ||
921 | return -1; | ||
922 | |||
923 | /* get the atapi capabilities page */ | ||
924 | pcd_probe_capabilities(); | ||
925 | |||
926 | if (register_blkdev(major, name)) { | ||
927 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) | ||
928 | put_disk(cd->disk); | ||
929 | return -1; | ||
930 | } | ||
931 | |||
932 | pcd_queue = blk_init_queue(do_pcd_request, &pcd_lock); | ||
933 | if (!pcd_queue) { | ||
934 | unregister_blkdev(major, name); | ||
935 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) | ||
936 | put_disk(cd->disk); | ||
937 | return -1; | ||
938 | } | ||
939 | |||
940 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { | ||
941 | if (cd->present) { | ||
942 | register_cdrom(&cd->info); | ||
943 | cd->disk->private_data = cd; | ||
944 | cd->disk->queue = pcd_queue; | ||
945 | add_disk(cd->disk); | ||
946 | } | ||
947 | } | ||
948 | |||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static void __exit pcd_exit(void) | ||
953 | { | ||
954 | struct pcd_unit *cd; | ||
955 | int unit; | ||
956 | |||
957 | for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { | ||
958 | if (cd->present) { | ||
959 | del_gendisk(cd->disk); | ||
960 | pi_release(cd->pi); | ||
961 | unregister_cdrom(&cd->info); | ||
962 | } | ||
963 | put_disk(cd->disk); | ||
964 | } | ||
965 | blk_cleanup_queue(pcd_queue); | ||
966 | unregister_blkdev(major, name); | ||
967 | } | ||
968 | |||
969 | MODULE_LICENSE("GPL"); | ||
970 | module_init(pcd_init) | ||
971 | module_exit(pcd_exit) | ||
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c new file mode 100644 index 000000000000..202a5a74ad37 --- /dev/null +++ b/drivers/block/paride/pd.c | |||
@@ -0,0 +1,950 @@ | |||
1 | /* | ||
2 | pd.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is the high-level driver for parallel port IDE hard | ||
6 | drives based on chips supported by the paride module. | ||
7 | |||
8 | By default, the driver will autoprobe for a single parallel | ||
9 | port IDE drive, but if their individual parameters are | ||
10 | specified, the driver can handle up to 4 drives. | ||
11 | |||
12 | The behaviour of the pd driver can be altered by setting | ||
13 | some parameters from the insmod command line. The following | ||
14 | parameters are adjustable: | ||
15 | |||
16 | drive0 These four arguments can be arrays of | ||
17 | drive1 1-8 integers as follows: | ||
18 | drive2 | ||
19 | drive3 <prt>,<pro>,<uni>,<mod>,<geo>,<sby>,<dly>,<slv> | ||
20 | |||
21 | Where, | ||
22 | |||
23 | <prt> is the base of the parallel port address for | ||
24 | the corresponding drive. (required) | ||
25 | |||
26 | <pro> is the protocol number for the adapter that | ||
27 | supports this drive. These numbers are | ||
28 | logged by 'paride' when the protocol modules | ||
29 | are initialised. (0 if not given) | ||
30 | |||
31 | <uni> for those adapters that support chained | ||
32 | devices, this is the unit selector for the | ||
33 | chain of devices on the given port. It should | ||
34 | be zero for devices that don't support chaining. | ||
35 | (0 if not given) | ||
36 | |||
37 | <mod> this can be -1 to choose the best mode, or one | ||
38 | of the mode numbers supported by the adapter. | ||
39 | (-1 if not given) | ||
40 | |||
41 | <geo> this defaults to 0 to indicate that the driver | ||
42 | should use the CHS geometry provided by the drive | ||
43 | itself. If set to 1, the driver will provide | ||
44 | a logical geometry with 64 heads and 32 sectors | ||
45 | per track, to be consistent with most SCSI | ||
46 | drivers. (0 if not given) | ||
47 | |||
48 | <sby> set this to zero to disable the power saving | ||
49 | standby mode, if needed. (1 if not given) | ||
50 | |||
51 | <dly> some parallel ports require the driver to | ||
52 | go more slowly. -1 sets a default value that | ||
53 | should work with the chosen protocol. Otherwise, | ||
54 | set this to a small integer, the larger it is | ||
55 | the slower the port i/o. In some cases, setting | ||
56 | this to zero will speed up the device. (default -1) | ||
57 | |||
58 | <slv> IDE disks can be jumpered to master or slave. | ||
59 | Set this to 0 to choose the master drive, 1 to | ||
60 | choose the slave, -1 (the default) to choose the | ||
61 | first drive found. | ||
62 | |||
63 | |||
64 | major You may use this parameter to overide the | ||
65 | default major number (45) that this driver | ||
66 | will use. Be sure to change the device | ||
67 | name as well. | ||
68 | |||
69 | name This parameter is a character string that | ||
70 | contains the name the kernel will use for this | ||
71 | device (in /proc output, for instance). | ||
72 | (default "pd") | ||
73 | |||
74 | cluster The driver will attempt to aggregate requests | ||
75 | for adjacent blocks into larger multi-block | ||
76 | clusters. The maximum cluster size (in 512 | ||
77 | byte sectors) is set with this parameter. | ||
78 | (default 64) | ||
79 | |||
80 | verbose This parameter controls the amount of logging | ||
81 | that the driver will do. Set it to 0 for | ||
82 | normal operation, 1 to see autoprobe progress | ||
83 | messages, or 2 to see additional debugging | ||
84 | output. (default 0) | ||
85 | |||
86 | nice This parameter controls the driver's use of | ||
87 | idle CPU time, at the expense of some speed. | ||
88 | |||
89 | If this driver is built into the kernel, you can use kernel | ||
90 | the following command line parameters, with the same values | ||
91 | as the corresponding module parameters listed above: | ||
92 | |||
93 | pd.drive0 | ||
94 | pd.drive1 | ||
95 | pd.drive2 | ||
96 | pd.drive3 | ||
97 | pd.cluster | ||
98 | pd.nice | ||
99 | |||
100 | In addition, you can use the parameter pd.disable to disable | ||
101 | the driver entirely. | ||
102 | |||
103 | */ | ||
104 | |||
105 | /* Changes: | ||
106 | |||
107 | 1.01 GRG 1997.01.24 Restored pd_reset() | ||
108 | Added eject ioctl | ||
109 | 1.02 GRG 1998.05.06 SMP spinlock changes, | ||
110 | Added slave support | ||
111 | 1.03 GRG 1998.06.16 Eliminate an Ugh. | ||
112 | 1.04 GRG 1998.08.15 Extra debugging, use HZ in loop timing | ||
113 | 1.05 GRG 1998.09.24 Added jumbo support | ||
114 | |||
115 | */ | ||
116 | |||
117 | #define PD_VERSION "1.05" | ||
118 | #define PD_MAJOR 45 | ||
119 | #define PD_NAME "pd" | ||
120 | #define PD_UNITS 4 | ||
121 | |||
122 | /* Here are things one can override from the insmod command. | ||
123 | Most are autoprobed by paride unless set here. Verbose is off | ||
124 | by default. | ||
125 | |||
126 | */ | ||
127 | |||
128 | static int verbose = 0; | ||
129 | static int major = PD_MAJOR; | ||
130 | static char *name = PD_NAME; | ||
131 | static int cluster = 64; | ||
132 | static int nice = 0; | ||
133 | static int disable = 0; | ||
134 | |||
135 | static int drive0[8] = { 0, 0, 0, -1, 0, 1, -1, -1 }; | ||
136 | static int drive1[8] = { 0, 0, 0, -1, 0, 1, -1, -1 }; | ||
137 | static int drive2[8] = { 0, 0, 0, -1, 0, 1, -1, -1 }; | ||
138 | static int drive3[8] = { 0, 0, 0, -1, 0, 1, -1, -1 }; | ||
139 | |||
140 | static int (*drives[4])[8] = {&drive0, &drive1, &drive2, &drive3}; | ||
141 | |||
142 | enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; | ||
143 | |||
144 | /* end of parameters */ | ||
145 | |||
146 | #include <linux/init.h> | ||
147 | #include <linux/module.h> | ||
148 | #include <linux/fs.h> | ||
149 | #include <linux/delay.h> | ||
150 | #include <linux/hdreg.h> | ||
151 | #include <linux/cdrom.h> /* for the eject ioctl */ | ||
152 | #include <linux/blkdev.h> | ||
153 | #include <linux/blkpg.h> | ||
154 | #include <asm/uaccess.h> | ||
155 | #include <linux/sched.h> | ||
156 | #include <linux/workqueue.h> | ||
157 | |||
158 | static DEFINE_SPINLOCK(pd_lock); | ||
159 | |||
160 | module_param(verbose, bool, 0); | ||
161 | module_param(major, int, 0); | ||
162 | module_param(name, charp, 0); | ||
163 | module_param(cluster, int, 0); | ||
164 | module_param(nice, int, 0); | ||
165 | module_param_array(drive0, int, NULL, 0); | ||
166 | module_param_array(drive1, int, NULL, 0); | ||
167 | module_param_array(drive2, int, NULL, 0); | ||
168 | module_param_array(drive3, int, NULL, 0); | ||
169 | |||
170 | #include "paride.h" | ||
171 | |||
172 | #define PD_BITS 4 | ||
173 | |||
174 | /* numbers for "SCSI" geometry */ | ||
175 | |||
176 | #define PD_LOG_HEADS 64 | ||
177 | #define PD_LOG_SECTS 32 | ||
178 | |||
179 | #define PD_ID_OFF 54 | ||
180 | #define PD_ID_LEN 14 | ||
181 | |||
182 | #define PD_MAX_RETRIES 5 | ||
183 | #define PD_TMO 800 /* interrupt timeout in jiffies */ | ||
184 | #define PD_SPIN_DEL 50 /* spin delay in micro-seconds */ | ||
185 | |||
186 | #define PD_SPIN (1000000*PD_TMO)/(HZ*PD_SPIN_DEL) | ||
187 | |||
188 | #define STAT_ERR 0x00001 | ||
189 | #define STAT_INDEX 0x00002 | ||
190 | #define STAT_ECC 0x00004 | ||
191 | #define STAT_DRQ 0x00008 | ||
192 | #define STAT_SEEK 0x00010 | ||
193 | #define STAT_WRERR 0x00020 | ||
194 | #define STAT_READY 0x00040 | ||
195 | #define STAT_BUSY 0x00080 | ||
196 | |||
197 | #define ERR_AMNF 0x00100 | ||
198 | #define ERR_TK0NF 0x00200 | ||
199 | #define ERR_ABRT 0x00400 | ||
200 | #define ERR_MCR 0x00800 | ||
201 | #define ERR_IDNF 0x01000 | ||
202 | #define ERR_MC 0x02000 | ||
203 | #define ERR_UNC 0x04000 | ||
204 | #define ERR_TMO 0x10000 | ||
205 | |||
206 | #define IDE_READ 0x20 | ||
207 | #define IDE_WRITE 0x30 | ||
208 | #define IDE_READ_VRFY 0x40 | ||
209 | #define IDE_INIT_DEV_PARMS 0x91 | ||
210 | #define IDE_STANDBY 0x96 | ||
211 | #define IDE_ACKCHANGE 0xdb | ||
212 | #define IDE_DOORLOCK 0xde | ||
213 | #define IDE_DOORUNLOCK 0xdf | ||
214 | #define IDE_IDENTIFY 0xec | ||
215 | #define IDE_EJECT 0xed | ||
216 | |||
217 | #define PD_NAMELEN 8 | ||
218 | |||
219 | struct pd_unit { | ||
220 | struct pi_adapter pia; /* interface to paride layer */ | ||
221 | struct pi_adapter *pi; | ||
222 | int access; /* count of active opens ... */ | ||
223 | int capacity; /* Size of this volume in sectors */ | ||
224 | int heads; /* physical geometry */ | ||
225 | int sectors; | ||
226 | int cylinders; | ||
227 | int can_lba; | ||
228 | int drive; /* master=0 slave=1 */ | ||
229 | int changed; /* Have we seen a disk change ? */ | ||
230 | int removable; /* removable media device ? */ | ||
231 | int standby; | ||
232 | int alt_geom; | ||
233 | char name[PD_NAMELEN]; /* pda, pdb, etc ... */ | ||
234 | struct gendisk *gd; | ||
235 | }; | ||
236 | |||
237 | static struct pd_unit pd[PD_UNITS]; | ||
238 | |||
239 | static char pd_scratch[512]; /* scratch block buffer */ | ||
240 | |||
241 | static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR", | ||
242 | "READY", "BUSY", "AMNF", "TK0NF", "ABRT", "MCR", | ||
243 | "IDNF", "MC", "UNC", "???", "TMO" | ||
244 | }; | ||
245 | |||
246 | static inline int status_reg(struct pd_unit *disk) | ||
247 | { | ||
248 | return pi_read_regr(disk->pi, 1, 6); | ||
249 | } | ||
250 | |||
251 | static inline int read_reg(struct pd_unit *disk, int reg) | ||
252 | { | ||
253 | return pi_read_regr(disk->pi, 0, reg); | ||
254 | } | ||
255 | |||
256 | static inline void write_status(struct pd_unit *disk, int val) | ||
257 | { | ||
258 | pi_write_regr(disk->pi, 1, 6, val); | ||
259 | } | ||
260 | |||
261 | static inline void write_reg(struct pd_unit *disk, int reg, int val) | ||
262 | { | ||
263 | pi_write_regr(disk->pi, 0, reg, val); | ||
264 | } | ||
265 | |||
266 | static inline u8 DRIVE(struct pd_unit *disk) | ||
267 | { | ||
268 | return 0xa0+0x10*disk->drive; | ||
269 | } | ||
270 | |||
271 | /* ide command interface */ | ||
272 | |||
273 | static void pd_print_error(struct pd_unit *disk, char *msg, int status) | ||
274 | { | ||
275 | int i; | ||
276 | |||
277 | printk("%s: %s: status = 0x%x =", disk->name, msg, status); | ||
278 | for (i = 0; i < 18; i++) | ||
279 | if (status & (1 << i)) | ||
280 | printk(" %s", pd_errs[i]); | ||
281 | printk("\n"); | ||
282 | } | ||
283 | |||
284 | static void pd_reset(struct pd_unit *disk) | ||
285 | { /* called only for MASTER drive */ | ||
286 | write_status(disk, 4); | ||
287 | udelay(50); | ||
288 | write_status(disk, 0); | ||
289 | udelay(250); | ||
290 | } | ||
291 | |||
292 | #define DBMSG(msg) ((verbose>1)?(msg):NULL) | ||
293 | |||
294 | static int pd_wait_for(struct pd_unit *disk, int w, char *msg) | ||
295 | { /* polled wait */ | ||
296 | int k, r, e; | ||
297 | |||
298 | k = 0; | ||
299 | while (k < PD_SPIN) { | ||
300 | r = status_reg(disk); | ||
301 | k++; | ||
302 | if (((r & w) == w) && !(r & STAT_BUSY)) | ||
303 | break; | ||
304 | udelay(PD_SPIN_DEL); | ||
305 | } | ||
306 | e = (read_reg(disk, 1) << 8) + read_reg(disk, 7); | ||
307 | if (k >= PD_SPIN) | ||
308 | e |= ERR_TMO; | ||
309 | if ((e & (STAT_ERR | ERR_TMO)) && (msg != NULL)) | ||
310 | pd_print_error(disk, msg, e); | ||
311 | return e; | ||
312 | } | ||
313 | |||
314 | static void pd_send_command(struct pd_unit *disk, int n, int s, int h, int c0, int c1, int func) | ||
315 | { | ||
316 | write_reg(disk, 6, DRIVE(disk) + h); | ||
317 | write_reg(disk, 1, 0); /* the IDE task file */ | ||
318 | write_reg(disk, 2, n); | ||
319 | write_reg(disk, 3, s); | ||
320 | write_reg(disk, 4, c0); | ||
321 | write_reg(disk, 5, c1); | ||
322 | write_reg(disk, 7, func); | ||
323 | |||
324 | udelay(1); | ||
325 | } | ||
326 | |||
327 | static void pd_ide_command(struct pd_unit *disk, int func, int block, int count) | ||
328 | { | ||
329 | int c1, c0, h, s; | ||
330 | |||
331 | if (disk->can_lba) { | ||
332 | s = block & 255; | ||
333 | c0 = (block >>= 8) & 255; | ||
334 | c1 = (block >>= 8) & 255; | ||
335 | h = ((block >>= 8) & 15) + 0x40; | ||
336 | } else { | ||
337 | s = (block % disk->sectors) + 1; | ||
338 | h = (block /= disk->sectors) % disk->heads; | ||
339 | c0 = (block /= disk->heads) % 256; | ||
340 | c1 = (block >>= 8); | ||
341 | } | ||
342 | pd_send_command(disk, count, s, h, c0, c1, func); | ||
343 | } | ||
344 | |||
345 | /* The i/o request engine */ | ||
346 | |||
347 | enum action {Fail = 0, Ok = 1, Hold, Wait}; | ||
348 | |||
349 | static struct request *pd_req; /* current request */ | ||
350 | static enum action (*phase)(void); | ||
351 | |||
352 | static void run_fsm(void); | ||
353 | |||
354 | static void ps_tq_int( void *data); | ||
355 | |||
356 | static DECLARE_WORK(fsm_tq, ps_tq_int, NULL); | ||
357 | |||
358 | static void schedule_fsm(void) | ||
359 | { | ||
360 | if (!nice) | ||
361 | schedule_work(&fsm_tq); | ||
362 | else | ||
363 | schedule_delayed_work(&fsm_tq, nice-1); | ||
364 | } | ||
365 | |||
366 | static void ps_tq_int(void *data) | ||
367 | { | ||
368 | run_fsm(); | ||
369 | } | ||
370 | |||
371 | static enum action do_pd_io_start(void); | ||
372 | static enum action pd_special(void); | ||
373 | static enum action do_pd_read_start(void); | ||
374 | static enum action do_pd_write_start(void); | ||
375 | static enum action do_pd_read_drq(void); | ||
376 | static enum action do_pd_write_done(void); | ||
377 | |||
378 | static struct request_queue *pd_queue; | ||
379 | static int pd_claimed; | ||
380 | |||
381 | static struct pd_unit *pd_current; /* current request's drive */ | ||
382 | static PIA *pi_current; /* current request's PIA */ | ||
383 | |||
384 | static void run_fsm(void) | ||
385 | { | ||
386 | while (1) { | ||
387 | enum action res; | ||
388 | unsigned long saved_flags; | ||
389 | int stop = 0; | ||
390 | |||
391 | if (!phase) { | ||
392 | pd_current = pd_req->rq_disk->private_data; | ||
393 | pi_current = pd_current->pi; | ||
394 | phase = do_pd_io_start; | ||
395 | } | ||
396 | |||
397 | switch (pd_claimed) { | ||
398 | case 0: | ||
399 | pd_claimed = 1; | ||
400 | if (!pi_schedule_claimed(pi_current, run_fsm)) | ||
401 | return; | ||
402 | case 1: | ||
403 | pd_claimed = 2; | ||
404 | pi_current->proto->connect(pi_current); | ||
405 | } | ||
406 | |||
407 | switch(res = phase()) { | ||
408 | case Ok: case Fail: | ||
409 | pi_disconnect(pi_current); | ||
410 | pd_claimed = 0; | ||
411 | phase = NULL; | ||
412 | spin_lock_irqsave(&pd_lock, saved_flags); | ||
413 | end_request(pd_req, res); | ||
414 | pd_req = elv_next_request(pd_queue); | ||
415 | if (!pd_req) | ||
416 | stop = 1; | ||
417 | spin_unlock_irqrestore(&pd_lock, saved_flags); | ||
418 | if (stop) | ||
419 | return; | ||
420 | case Hold: | ||
421 | schedule_fsm(); | ||
422 | return; | ||
423 | case Wait: | ||
424 | pi_disconnect(pi_current); | ||
425 | pd_claimed = 0; | ||
426 | } | ||
427 | } | ||
428 | } | ||
429 | |||
430 | static int pd_retries = 0; /* i/o error retry count */ | ||
431 | static int pd_block; /* address of next requested block */ | ||
432 | static int pd_count; /* number of blocks still to do */ | ||
433 | static int pd_run; /* sectors in current cluster */ | ||
434 | static int pd_cmd; /* current command READ/WRITE */ | ||
435 | static char *pd_buf; /* buffer for request in progress */ | ||
436 | |||
437 | static enum action do_pd_io_start(void) | ||
438 | { | ||
439 | if (pd_req->flags & REQ_SPECIAL) { | ||
440 | phase = pd_special; | ||
441 | return pd_special(); | ||
442 | } | ||
443 | |||
444 | pd_cmd = rq_data_dir(pd_req); | ||
445 | if (pd_cmd == READ || pd_cmd == WRITE) { | ||
446 | pd_block = pd_req->sector; | ||
447 | pd_count = pd_req->current_nr_sectors; | ||
448 | if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) | ||
449 | return Fail; | ||
450 | pd_run = pd_req->nr_sectors; | ||
451 | pd_buf = pd_req->buffer; | ||
452 | pd_retries = 0; | ||
453 | if (pd_cmd == READ) | ||
454 | return do_pd_read_start(); | ||
455 | else | ||
456 | return do_pd_write_start(); | ||
457 | } | ||
458 | return Fail; | ||
459 | } | ||
460 | |||
461 | static enum action pd_special(void) | ||
462 | { | ||
463 | enum action (*func)(struct pd_unit *) = pd_req->special; | ||
464 | return func(pd_current); | ||
465 | } | ||
466 | |||
467 | static int pd_next_buf(void) | ||
468 | { | ||
469 | unsigned long saved_flags; | ||
470 | |||
471 | pd_count--; | ||
472 | pd_run--; | ||
473 | pd_buf += 512; | ||
474 | pd_block++; | ||
475 | if (!pd_run) | ||
476 | return 1; | ||
477 | if (pd_count) | ||
478 | return 0; | ||
479 | spin_lock_irqsave(&pd_lock, saved_flags); | ||
480 | end_request(pd_req, 1); | ||
481 | pd_count = pd_req->current_nr_sectors; | ||
482 | pd_buf = pd_req->buffer; | ||
483 | spin_unlock_irqrestore(&pd_lock, saved_flags); | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static unsigned long pd_timeout; | ||
488 | |||
489 | static enum action do_pd_read_start(void) | ||
490 | { | ||
491 | if (pd_wait_for(pd_current, STAT_READY, "do_pd_read") & STAT_ERR) { | ||
492 | if (pd_retries < PD_MAX_RETRIES) { | ||
493 | pd_retries++; | ||
494 | return Wait; | ||
495 | } | ||
496 | return Fail; | ||
497 | } | ||
498 | pd_ide_command(pd_current, IDE_READ, pd_block, pd_run); | ||
499 | phase = do_pd_read_drq; | ||
500 | pd_timeout = jiffies + PD_TMO; | ||
501 | return Hold; | ||
502 | } | ||
503 | |||
504 | static enum action do_pd_write_start(void) | ||
505 | { | ||
506 | if (pd_wait_for(pd_current, STAT_READY, "do_pd_write") & STAT_ERR) { | ||
507 | if (pd_retries < PD_MAX_RETRIES) { | ||
508 | pd_retries++; | ||
509 | return Wait; | ||
510 | } | ||
511 | return Fail; | ||
512 | } | ||
513 | pd_ide_command(pd_current, IDE_WRITE, pd_block, pd_run); | ||
514 | while (1) { | ||
515 | if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_write_drq") & STAT_ERR) { | ||
516 | if (pd_retries < PD_MAX_RETRIES) { | ||
517 | pd_retries++; | ||
518 | return Wait; | ||
519 | } | ||
520 | return Fail; | ||
521 | } | ||
522 | pi_write_block(pd_current->pi, pd_buf, 512); | ||
523 | if (pd_next_buf()) | ||
524 | break; | ||
525 | } | ||
526 | phase = do_pd_write_done; | ||
527 | pd_timeout = jiffies + PD_TMO; | ||
528 | return Hold; | ||
529 | } | ||
530 | |||
531 | static inline int pd_ready(void) | ||
532 | { | ||
533 | return !(status_reg(pd_current) & STAT_BUSY); | ||
534 | } | ||
535 | |||
536 | static enum action do_pd_read_drq(void) | ||
537 | { | ||
538 | if (!pd_ready() && !time_after_eq(jiffies, pd_timeout)) | ||
539 | return Hold; | ||
540 | |||
541 | while (1) { | ||
542 | if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_read_drq") & STAT_ERR) { | ||
543 | if (pd_retries < PD_MAX_RETRIES) { | ||
544 | pd_retries++; | ||
545 | phase = do_pd_read_start; | ||
546 | return Wait; | ||
547 | } | ||
548 | return Fail; | ||
549 | } | ||
550 | pi_read_block(pd_current->pi, pd_buf, 512); | ||
551 | if (pd_next_buf()) | ||
552 | break; | ||
553 | } | ||
554 | return Ok; | ||
555 | } | ||
556 | |||
557 | static enum action do_pd_write_done(void) | ||
558 | { | ||
559 | if (!pd_ready() && !time_after_eq(jiffies, pd_timeout)) | ||
560 | return Hold; | ||
561 | |||
562 | if (pd_wait_for(pd_current, STAT_READY, "do_pd_write_done") & STAT_ERR) { | ||
563 | if (pd_retries < PD_MAX_RETRIES) { | ||
564 | pd_retries++; | ||
565 | phase = do_pd_write_start; | ||
566 | return Wait; | ||
567 | } | ||
568 | return Fail; | ||
569 | } | ||
570 | return Ok; | ||
571 | } | ||
572 | |||
573 | /* special io requests */ | ||
574 | |||
575 | /* According to the ATA standard, the default CHS geometry should be | ||
576 | available following a reset. Some Western Digital drives come up | ||
577 | in a mode where only LBA addresses are accepted until the device | ||
578 | parameters are initialised. | ||
579 | */ | ||
580 | |||
581 | static void pd_init_dev_parms(struct pd_unit *disk) | ||
582 | { | ||
583 | pd_wait_for(disk, 0, DBMSG("before init_dev_parms")); | ||
584 | pd_send_command(disk, disk->sectors, 0, disk->heads - 1, 0, 0, | ||
585 | IDE_INIT_DEV_PARMS); | ||
586 | udelay(300); | ||
587 | pd_wait_for(disk, 0, "Initialise device parameters"); | ||
588 | } | ||
589 | |||
590 | static enum action pd_door_lock(struct pd_unit *disk) | ||
591 | { | ||
592 | if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) { | ||
593 | pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORLOCK); | ||
594 | pd_wait_for(disk, STAT_READY, "Lock done"); | ||
595 | } | ||
596 | return Ok; | ||
597 | } | ||
598 | |||
599 | static enum action pd_door_unlock(struct pd_unit *disk) | ||
600 | { | ||
601 | if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) { | ||
602 | pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK); | ||
603 | pd_wait_for(disk, STAT_READY, "Lock done"); | ||
604 | } | ||
605 | return Ok; | ||
606 | } | ||
607 | |||
608 | static enum action pd_eject(struct pd_unit *disk) | ||
609 | { | ||
610 | pd_wait_for(disk, 0, DBMSG("before unlock on eject")); | ||
611 | pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK); | ||
612 | pd_wait_for(disk, 0, DBMSG("after unlock on eject")); | ||
613 | pd_wait_for(disk, 0, DBMSG("before eject")); | ||
614 | pd_send_command(disk, 0, 0, 0, 0, 0, IDE_EJECT); | ||
615 | pd_wait_for(disk, 0, DBMSG("after eject")); | ||
616 | return Ok; | ||
617 | } | ||
618 | |||
619 | static enum action pd_media_check(struct pd_unit *disk) | ||
620 | { | ||
621 | int r = pd_wait_for(disk, STAT_READY, DBMSG("before media_check")); | ||
622 | if (!(r & STAT_ERR)) { | ||
623 | pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY); | ||
624 | r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after READ_VRFY")); | ||
625 | } else | ||
626 | disk->changed = 1; /* say changed if other error */ | ||
627 | if (r & ERR_MC) { | ||
628 | disk->changed = 1; | ||
629 | pd_send_command(disk, 1, 0, 0, 0, 0, IDE_ACKCHANGE); | ||
630 | pd_wait_for(disk, STAT_READY, DBMSG("RDY after ACKCHANGE")); | ||
631 | pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY); | ||
632 | r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after VRFY")); | ||
633 | } | ||
634 | return Ok; | ||
635 | } | ||
636 | |||
637 | static void pd_standby_off(struct pd_unit *disk) | ||
638 | { | ||
639 | pd_wait_for(disk, 0, DBMSG("before STANDBY")); | ||
640 | pd_send_command(disk, 0, 0, 0, 0, 0, IDE_STANDBY); | ||
641 | pd_wait_for(disk, 0, DBMSG("after STANDBY")); | ||
642 | } | ||
643 | |||
644 | static enum action pd_identify(struct pd_unit *disk) | ||
645 | { | ||
646 | int j; | ||
647 | char id[PD_ID_LEN + 1]; | ||
648 | |||
649 | /* WARNING: here there may be dragons. reset() applies to both drives, | ||
650 | but we call it only on probing the MASTER. This should allow most | ||
651 | common configurations to work, but be warned that a reset can clear | ||
652 | settings on the SLAVE drive. | ||
653 | */ | ||
654 | |||
655 | if (disk->drive == 0) | ||
656 | pd_reset(disk); | ||
657 | |||
658 | write_reg(disk, 6, DRIVE(disk)); | ||
659 | pd_wait_for(disk, 0, DBMSG("before IDENT")); | ||
660 | pd_send_command(disk, 1, 0, 0, 0, 0, IDE_IDENTIFY); | ||
661 | |||
662 | if (pd_wait_for(disk, STAT_DRQ, DBMSG("IDENT DRQ")) & STAT_ERR) | ||
663 | return Fail; | ||
664 | pi_read_block(disk->pi, pd_scratch, 512); | ||
665 | disk->can_lba = pd_scratch[99] & 2; | ||
666 | disk->sectors = le16_to_cpu(*(u16 *) (pd_scratch + 12)); | ||
667 | disk->heads = le16_to_cpu(*(u16 *) (pd_scratch + 6)); | ||
668 | disk->cylinders = le16_to_cpu(*(u16 *) (pd_scratch + 2)); | ||
669 | if (disk->can_lba) | ||
670 | disk->capacity = le32_to_cpu(*(u32 *) (pd_scratch + 120)); | ||
671 | else | ||
672 | disk->capacity = disk->sectors * disk->heads * disk->cylinders; | ||
673 | |||
674 | for (j = 0; j < PD_ID_LEN; j++) | ||
675 | id[j ^ 1] = pd_scratch[j + PD_ID_OFF]; | ||
676 | j = PD_ID_LEN - 1; | ||
677 | while ((j >= 0) && (id[j] <= 0x20)) | ||
678 | j--; | ||
679 | j++; | ||
680 | id[j] = 0; | ||
681 | |||
682 | disk->removable = pd_scratch[0] & 0x80; | ||
683 | |||
684 | printk("%s: %s, %s, %d blocks [%dM], (%d/%d/%d), %s media\n", | ||
685 | disk->name, id, | ||
686 | disk->drive ? "slave" : "master", | ||
687 | disk->capacity, disk->capacity / 2048, | ||
688 | disk->cylinders, disk->heads, disk->sectors, | ||
689 | disk->removable ? "removable" : "fixed"); | ||
690 | |||
691 | if (disk->capacity) | ||
692 | pd_init_dev_parms(disk); | ||
693 | if (!disk->standby) | ||
694 | pd_standby_off(disk); | ||
695 | |||
696 | return Ok; | ||
697 | } | ||
698 | |||
699 | /* end of io request engine */ | ||
700 | |||
701 | static void do_pd_request(request_queue_t * q) | ||
702 | { | ||
703 | if (pd_req) | ||
704 | return; | ||
705 | pd_req = elv_next_request(q); | ||
706 | if (!pd_req) | ||
707 | return; | ||
708 | |||
709 | schedule_fsm(); | ||
710 | } | ||
711 | |||
712 | static int pd_special_command(struct pd_unit *disk, | ||
713 | enum action (*func)(struct pd_unit *disk)) | ||
714 | { | ||
715 | DECLARE_COMPLETION(wait); | ||
716 | struct request rq; | ||
717 | int err = 0; | ||
718 | |||
719 | memset(&rq, 0, sizeof(rq)); | ||
720 | rq.errors = 0; | ||
721 | rq.rq_status = RQ_ACTIVE; | ||
722 | rq.rq_disk = disk->gd; | ||
723 | rq.ref_count = 1; | ||
724 | rq.waiting = &wait; | ||
725 | rq.end_io = blk_end_sync_rq; | ||
726 | blk_insert_request(disk->gd->queue, &rq, 0, func, 0); | ||
727 | wait_for_completion(&wait); | ||
728 | rq.waiting = NULL; | ||
729 | if (rq.errors) | ||
730 | err = -EIO; | ||
731 | blk_put_request(&rq); | ||
732 | return err; | ||
733 | } | ||
734 | |||
735 | /* kernel glue structures */ | ||
736 | |||
737 | static int pd_open(struct inode *inode, struct file *file) | ||
738 | { | ||
739 | struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; | ||
740 | |||
741 | disk->access++; | ||
742 | |||
743 | if (disk->removable) { | ||
744 | pd_special_command(disk, pd_media_check); | ||
745 | pd_special_command(disk, pd_door_lock); | ||
746 | } | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int pd_ioctl(struct inode *inode, struct file *file, | ||
751 | unsigned int cmd, unsigned long arg) | ||
752 | { | ||
753 | struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; | ||
754 | struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; | ||
755 | struct hd_geometry g; | ||
756 | |||
757 | switch (cmd) { | ||
758 | case CDROMEJECT: | ||
759 | if (disk->access == 1) | ||
760 | pd_special_command(disk, pd_eject); | ||
761 | return 0; | ||
762 | case HDIO_GETGEO: | ||
763 | if (disk->alt_geom) { | ||
764 | g.heads = PD_LOG_HEADS; | ||
765 | g.sectors = PD_LOG_SECTS; | ||
766 | g.cylinders = disk->capacity / (g.heads * g.sectors); | ||
767 | } else { | ||
768 | g.heads = disk->heads; | ||
769 | g.sectors = disk->sectors; | ||
770 | g.cylinders = disk->cylinders; | ||
771 | } | ||
772 | g.start = get_start_sect(inode->i_bdev); | ||
773 | if (copy_to_user(geo, &g, sizeof(struct hd_geometry))) | ||
774 | return -EFAULT; | ||
775 | return 0; | ||
776 | default: | ||
777 | return -EINVAL; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | static int pd_release(struct inode *inode, struct file *file) | ||
782 | { | ||
783 | struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; | ||
784 | |||
785 | if (!--disk->access && disk->removable) | ||
786 | pd_special_command(disk, pd_door_unlock); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static int pd_check_media(struct gendisk *p) | ||
792 | { | ||
793 | struct pd_unit *disk = p->private_data; | ||
794 | int r; | ||
795 | if (!disk->removable) | ||
796 | return 0; | ||
797 | pd_special_command(disk, pd_media_check); | ||
798 | r = disk->changed; | ||
799 | disk->changed = 0; | ||
800 | return r; | ||
801 | } | ||
802 | |||
803 | static int pd_revalidate(struct gendisk *p) | ||
804 | { | ||
805 | struct pd_unit *disk = p->private_data; | ||
806 | if (pd_special_command(disk, pd_identify) == 0) | ||
807 | set_capacity(p, disk->capacity); | ||
808 | else | ||
809 | set_capacity(p, 0); | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static struct block_device_operations pd_fops = { | ||
814 | .owner = THIS_MODULE, | ||
815 | .open = pd_open, | ||
816 | .release = pd_release, | ||
817 | .ioctl = pd_ioctl, | ||
818 | .media_changed = pd_check_media, | ||
819 | .revalidate_disk= pd_revalidate | ||
820 | }; | ||
821 | |||
822 | /* probing */ | ||
823 | |||
824 | static void pd_probe_drive(struct pd_unit *disk) | ||
825 | { | ||
826 | struct gendisk *p = alloc_disk(1 << PD_BITS); | ||
827 | if (!p) | ||
828 | return; | ||
829 | strcpy(p->disk_name, disk->name); | ||
830 | p->fops = &pd_fops; | ||
831 | p->major = major; | ||
832 | p->first_minor = (disk - pd) << PD_BITS; | ||
833 | disk->gd = p; | ||
834 | p->private_data = disk; | ||
835 | p->queue = pd_queue; | ||
836 | |||
837 | if (disk->drive == -1) { | ||
838 | for (disk->drive = 0; disk->drive <= 1; disk->drive++) | ||
839 | if (pd_special_command(disk, pd_identify) == 0) | ||
840 | return; | ||
841 | } else if (pd_special_command(disk, pd_identify) == 0) | ||
842 | return; | ||
843 | disk->gd = NULL; | ||
844 | put_disk(p); | ||
845 | } | ||
846 | |||
847 | static int pd_detect(void) | ||
848 | { | ||
849 | int found = 0, unit, pd_drive_count = 0; | ||
850 | struct pd_unit *disk; | ||
851 | |||
852 | for (unit = 0; unit < PD_UNITS; unit++) { | ||
853 | int *parm = *drives[unit]; | ||
854 | struct pd_unit *disk = pd + unit; | ||
855 | disk->pi = &disk->pia; | ||
856 | disk->access = 0; | ||
857 | disk->changed = 1; | ||
858 | disk->capacity = 0; | ||
859 | disk->drive = parm[D_SLV]; | ||
860 | snprintf(disk->name, PD_NAMELEN, "%s%c", name, 'a'+unit); | ||
861 | disk->alt_geom = parm[D_GEO]; | ||
862 | disk->standby = parm[D_SBY]; | ||
863 | if (parm[D_PRT]) | ||
864 | pd_drive_count++; | ||
865 | } | ||
866 | |||
867 | if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ | ||
868 | disk = pd; | ||
869 | if (pi_init(disk->pi, 1, -1, -1, -1, -1, -1, pd_scratch, | ||
870 | PI_PD, verbose, disk->name)) { | ||
871 | pd_probe_drive(disk); | ||
872 | if (!disk->gd) | ||
873 | pi_release(disk->pi); | ||
874 | } | ||
875 | |||
876 | } else { | ||
877 | for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { | ||
878 | int *parm = *drives[unit]; | ||
879 | if (!parm[D_PRT]) | ||
880 | continue; | ||
881 | if (pi_init(disk->pi, 0, parm[D_PRT], parm[D_MOD], | ||
882 | parm[D_UNI], parm[D_PRO], parm[D_DLY], | ||
883 | pd_scratch, PI_PD, verbose, disk->name)) { | ||
884 | pd_probe_drive(disk); | ||
885 | if (!disk->gd) | ||
886 | pi_release(disk->pi); | ||
887 | } | ||
888 | } | ||
889 | } | ||
890 | for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { | ||
891 | if (disk->gd) { | ||
892 | set_capacity(disk->gd, disk->capacity); | ||
893 | add_disk(disk->gd); | ||
894 | found = 1; | ||
895 | } | ||
896 | } | ||
897 | if (!found) | ||
898 | printk("%s: no valid drive found\n", name); | ||
899 | return found; | ||
900 | } | ||
901 | |||
902 | static int __init pd_init(void) | ||
903 | { | ||
904 | if (disable) | ||
905 | goto out1; | ||
906 | |||
907 | pd_queue = blk_init_queue(do_pd_request, &pd_lock); | ||
908 | if (!pd_queue) | ||
909 | goto out1; | ||
910 | |||
911 | blk_queue_max_sectors(pd_queue, cluster); | ||
912 | |||
913 | if (register_blkdev(major, name)) | ||
914 | goto out2; | ||
915 | |||
916 | printk("%s: %s version %s, major %d, cluster %d, nice %d\n", | ||
917 | name, name, PD_VERSION, major, cluster, nice); | ||
918 | if (!pd_detect()) | ||
919 | goto out3; | ||
920 | |||
921 | return 0; | ||
922 | |||
923 | out3: | ||
924 | unregister_blkdev(major, name); | ||
925 | out2: | ||
926 | blk_cleanup_queue(pd_queue); | ||
927 | out1: | ||
928 | return -ENODEV; | ||
929 | } | ||
930 | |||
931 | static void __exit pd_exit(void) | ||
932 | { | ||
933 | struct pd_unit *disk; | ||
934 | int unit; | ||
935 | unregister_blkdev(major, name); | ||
936 | for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { | ||
937 | struct gendisk *p = disk->gd; | ||
938 | if (p) { | ||
939 | disk->gd = NULL; | ||
940 | del_gendisk(p); | ||
941 | put_disk(p); | ||
942 | pi_release(disk->pi); | ||
943 | } | ||
944 | } | ||
945 | blk_cleanup_queue(pd_queue); | ||
946 | } | ||
947 | |||
948 | MODULE_LICENSE("GPL"); | ||
949 | module_init(pd_init) | ||
950 | module_exit(pd_exit) | ||
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c new file mode 100644 index 000000000000..060b1f2a91dd --- /dev/null +++ b/drivers/block/paride/pf.c | |||
@@ -0,0 +1,982 @@ | |||
1 | /* | ||
2 | pf.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is the high-level driver for parallel port ATAPI disk | ||
6 | drives based on chips supported by the paride module. | ||
7 | |||
8 | By default, the driver will autoprobe for a single parallel | ||
9 | port ATAPI disk drive, but if their individual parameters are | ||
10 | specified, the driver can handle up to 4 drives. | ||
11 | |||
12 | The behaviour of the pf driver can be altered by setting | ||
13 | some parameters from the insmod command line. The following | ||
14 | parameters are adjustable: | ||
15 | |||
16 | drive0 These four arguments can be arrays of | ||
17 | drive1 1-7 integers as follows: | ||
18 | drive2 | ||
19 | drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<lun>,<dly> | ||
20 | |||
21 | Where, | ||
22 | |||
23 | <prt> is the base of the parallel port address for | ||
24 | the corresponding drive. (required) | ||
25 | |||
26 | <pro> is the protocol number for the adapter that | ||
27 | supports this drive. These numbers are | ||
28 | logged by 'paride' when the protocol modules | ||
29 | are initialised. (0 if not given) | ||
30 | |||
31 | <uni> for those adapters that support chained | ||
32 | devices, this is the unit selector for the | ||
33 | chain of devices on the given port. It should | ||
34 | be zero for devices that don't support chaining. | ||
35 | (0 if not given) | ||
36 | |||
37 | <mod> this can be -1 to choose the best mode, or one | ||
38 | of the mode numbers supported by the adapter. | ||
39 | (-1 if not given) | ||
40 | |||
41 | <slv> ATAPI CDroms can be jumpered to master or slave. | ||
42 | Set this to 0 to choose the master drive, 1 to | ||
43 | choose the slave, -1 (the default) to choose the | ||
44 | first drive found. | ||
45 | |||
46 | <lun> Some ATAPI devices support multiple LUNs. | ||
47 | One example is the ATAPI PD/CD drive from | ||
48 | Matshita/Panasonic. This device has a | ||
49 | CD drive on LUN 0 and a PD drive on LUN 1. | ||
50 | By default, the driver will search for the | ||
51 | first LUN with a supported device. Set | ||
52 | this parameter to force it to use a specific | ||
53 | LUN. (default -1) | ||
54 | |||
55 | <dly> some parallel ports require the driver to | ||
56 | go more slowly. -1 sets a default value that | ||
57 | should work with the chosen protocol. Otherwise, | ||
58 | set this to a small integer, the larger it is | ||
59 | the slower the port i/o. In some cases, setting | ||
60 | this to zero will speed up the device. (default -1) | ||
61 | |||
62 | major You may use this parameter to overide the | ||
63 | default major number (47) that this driver | ||
64 | will use. Be sure to change the device | ||
65 | name as well. | ||
66 | |||
67 | name This parameter is a character string that | ||
68 | contains the name the kernel will use for this | ||
69 | device (in /proc output, for instance). | ||
70 | (default "pf"). | ||
71 | |||
72 | cluster The driver will attempt to aggregate requests | ||
73 | for adjacent blocks into larger multi-block | ||
74 | clusters. The maximum cluster size (in 512 | ||
75 | byte sectors) is set with this parameter. | ||
76 | (default 64) | ||
77 | |||
78 | verbose This parameter controls the amount of logging | ||
79 | that the driver will do. Set it to 0 for | ||
80 | normal operation, 1 to see autoprobe progress | ||
81 | messages, or 2 to see additional debugging | ||
82 | output. (default 0) | ||
83 | |||
84 | nice This parameter controls the driver's use of | ||
85 | idle CPU time, at the expense of some speed. | ||
86 | |||
87 | If this driver is built into the kernel, you can use the | ||
88 | following command line parameters, with the same values | ||
89 | as the corresponding module parameters listed above: | ||
90 | |||
91 | pf.drive0 | ||
92 | pf.drive1 | ||
93 | pf.drive2 | ||
94 | pf.drive3 | ||
95 | pf.cluster | ||
96 | pf.nice | ||
97 | |||
98 | In addition, you can use the parameter pf.disable to disable | ||
99 | the driver entirely. | ||
100 | |||
101 | */ | ||
102 | |||
103 | /* Changes: | ||
104 | |||
105 | 1.01 GRG 1998.05.03 Changes for SMP. Eliminate sti(). | ||
106 | Fix for drives that don't clear STAT_ERR | ||
107 | until after next CDB delivered. | ||
108 | Small change in pf_completion to round | ||
109 | up transfer size. | ||
110 | 1.02 GRG 1998.06.16 Eliminated an Ugh | ||
111 | 1.03 GRG 1998.08.16 Use HZ in loop timings, extra debugging | ||
112 | 1.04 GRG 1998.09.24 Added jumbo support | ||
113 | |||
114 | */ | ||
115 | |||
116 | #define PF_VERSION "1.04" | ||
117 | #define PF_MAJOR 47 | ||
118 | #define PF_NAME "pf" | ||
119 | #define PF_UNITS 4 | ||
120 | |||
121 | /* Here are things one can override from the insmod command. | ||
122 | Most are autoprobed by paride unless set here. Verbose is off | ||
123 | by default. | ||
124 | |||
125 | */ | ||
126 | |||
127 | static int verbose = 0; | ||
128 | static int major = PF_MAJOR; | ||
129 | static char *name = PF_NAME; | ||
130 | static int cluster = 64; | ||
131 | static int nice = 0; | ||
132 | static int disable = 0; | ||
133 | |||
134 | static int drive0[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
135 | static int drive1[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
136 | static int drive2[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
137 | static int drive3[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
138 | |||
139 | static int (*drives[4])[7] = {&drive0, &drive1, &drive2, &drive3}; | ||
140 | static int pf_drive_count; | ||
141 | |||
142 | enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY}; | ||
143 | |||
144 | /* end of parameters */ | ||
145 | |||
146 | #include <linux/module.h> | ||
147 | #include <linux/init.h> | ||
148 | #include <linux/fs.h> | ||
149 | #include <linux/delay.h> | ||
150 | #include <linux/hdreg.h> | ||
151 | #include <linux/cdrom.h> | ||
152 | #include <linux/spinlock.h> | ||
153 | #include <linux/blkdev.h> | ||
154 | #include <linux/blkpg.h> | ||
155 | #include <asm/uaccess.h> | ||
156 | |||
157 | static spinlock_t pf_spin_lock; | ||
158 | |||
159 | module_param(verbose, bool, 0644); | ||
160 | module_param(major, int, 0); | ||
161 | module_param(name, charp, 0); | ||
162 | module_param(cluster, int, 0); | ||
163 | module_param(nice, int, 0); | ||
164 | module_param_array(drive0, int, NULL, 0); | ||
165 | module_param_array(drive1, int, NULL, 0); | ||
166 | module_param_array(drive2, int, NULL, 0); | ||
167 | module_param_array(drive3, int, NULL, 0); | ||
168 | |||
169 | #include "paride.h" | ||
170 | #include "pseudo.h" | ||
171 | |||
172 | /* constants for faking geometry numbers */ | ||
173 | |||
174 | #define PF_FD_MAX 8192 /* use FD geometry under this size */ | ||
175 | #define PF_FD_HDS 2 | ||
176 | #define PF_FD_SPT 18 | ||
177 | #define PF_HD_HDS 64 | ||
178 | #define PF_HD_SPT 32 | ||
179 | |||
180 | #define PF_MAX_RETRIES 5 | ||
181 | #define PF_TMO 800 /* interrupt timeout in jiffies */ | ||
182 | #define PF_SPIN_DEL 50 /* spin delay in micro-seconds */ | ||
183 | |||
184 | #define PF_SPIN (1000000*PF_TMO)/(HZ*PF_SPIN_DEL) | ||
185 | |||
186 | #define STAT_ERR 0x00001 | ||
187 | #define STAT_INDEX 0x00002 | ||
188 | #define STAT_ECC 0x00004 | ||
189 | #define STAT_DRQ 0x00008 | ||
190 | #define STAT_SEEK 0x00010 | ||
191 | #define STAT_WRERR 0x00020 | ||
192 | #define STAT_READY 0x00040 | ||
193 | #define STAT_BUSY 0x00080 | ||
194 | |||
195 | #define ATAPI_REQ_SENSE 0x03 | ||
196 | #define ATAPI_LOCK 0x1e | ||
197 | #define ATAPI_DOOR 0x1b | ||
198 | #define ATAPI_MODE_SENSE 0x5a | ||
199 | #define ATAPI_CAPACITY 0x25 | ||
200 | #define ATAPI_IDENTIFY 0x12 | ||
201 | #define ATAPI_READ_10 0x28 | ||
202 | #define ATAPI_WRITE_10 0x2a | ||
203 | |||
204 | static int pf_open(struct inode *inode, struct file *file); | ||
205 | static void do_pf_request(request_queue_t * q); | ||
206 | static int pf_ioctl(struct inode *inode, struct file *file, | ||
207 | unsigned int cmd, unsigned long arg); | ||
208 | |||
209 | static int pf_release(struct inode *inode, struct file *file); | ||
210 | |||
211 | static int pf_detect(void); | ||
212 | static void do_pf_read(void); | ||
213 | static void do_pf_read_start(void); | ||
214 | static void do_pf_write(void); | ||
215 | static void do_pf_write_start(void); | ||
216 | static void do_pf_read_drq(void); | ||
217 | static void do_pf_write_done(void); | ||
218 | |||
219 | #define PF_NM 0 | ||
220 | #define PF_RO 1 | ||
221 | #define PF_RW 2 | ||
222 | |||
223 | #define PF_NAMELEN 8 | ||
224 | |||
225 | struct pf_unit { | ||
226 | struct pi_adapter pia; /* interface to paride layer */ | ||
227 | struct pi_adapter *pi; | ||
228 | int removable; /* removable media device ? */ | ||
229 | int media_status; /* media present ? WP ? */ | ||
230 | int drive; /* drive */ | ||
231 | int lun; | ||
232 | int access; /* count of active opens ... */ | ||
233 | int present; /* device present ? */ | ||
234 | char name[PF_NAMELEN]; /* pf0, pf1, ... */ | ||
235 | struct gendisk *disk; | ||
236 | }; | ||
237 | |||
238 | static struct pf_unit units[PF_UNITS]; | ||
239 | |||
240 | static int pf_identify(struct pf_unit *pf); | ||
241 | static void pf_lock(struct pf_unit *pf, int func); | ||
242 | static void pf_eject(struct pf_unit *pf); | ||
243 | static int pf_check_media(struct gendisk *disk); | ||
244 | |||
245 | static char pf_scratch[512]; /* scratch block buffer */ | ||
246 | |||
247 | /* the variables below are used mainly in the I/O request engine, which | ||
248 | processes only one request at a time. | ||
249 | */ | ||
250 | |||
251 | static int pf_retries = 0; /* i/o error retry count */ | ||
252 | static int pf_busy = 0; /* request being processed ? */ | ||
253 | static struct request *pf_req; /* current request */ | ||
254 | static int pf_block; /* address of next requested block */ | ||
255 | static int pf_count; /* number of blocks still to do */ | ||
256 | static int pf_run; /* sectors in current cluster */ | ||
257 | static int pf_cmd; /* current command READ/WRITE */ | ||
258 | static struct pf_unit *pf_current;/* unit of current request */ | ||
259 | static int pf_mask; /* stopper for pseudo-int */ | ||
260 | static char *pf_buf; /* buffer for request in progress */ | ||
261 | |||
262 | /* kernel glue structures */ | ||
263 | |||
264 | static struct block_device_operations pf_fops = { | ||
265 | .owner = THIS_MODULE, | ||
266 | .open = pf_open, | ||
267 | .release = pf_release, | ||
268 | .ioctl = pf_ioctl, | ||
269 | .media_changed = pf_check_media, | ||
270 | }; | ||
271 | |||
272 | static void __init pf_init_units(void) | ||
273 | { | ||
274 | struct pf_unit *pf; | ||
275 | int unit; | ||
276 | |||
277 | pf_drive_count = 0; | ||
278 | for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) { | ||
279 | struct gendisk *disk = alloc_disk(1); | ||
280 | if (!disk) | ||
281 | continue; | ||
282 | pf->disk = disk; | ||
283 | pf->pi = &pf->pia; | ||
284 | pf->media_status = PF_NM; | ||
285 | pf->drive = (*drives[unit])[D_SLV]; | ||
286 | pf->lun = (*drives[unit])[D_LUN]; | ||
287 | snprintf(pf->name, PF_NAMELEN, "%s%d", name, unit); | ||
288 | disk->major = major; | ||
289 | disk->first_minor = unit; | ||
290 | strcpy(disk->disk_name, pf->name); | ||
291 | disk->fops = &pf_fops; | ||
292 | if (!(*drives[unit])[D_PRT]) | ||
293 | pf_drive_count++; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | static int pf_open(struct inode *inode, struct file *file) | ||
298 | { | ||
299 | struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; | ||
300 | |||
301 | pf_identify(pf); | ||
302 | |||
303 | if (pf->media_status == PF_NM) | ||
304 | return -ENODEV; | ||
305 | |||
306 | if ((pf->media_status == PF_RO) && (file->f_mode & 2)) | ||
307 | return -EROFS; | ||
308 | |||
309 | pf->access++; | ||
310 | if (pf->removable) | ||
311 | pf_lock(pf, 1); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
317 | { | ||
318 | struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; | ||
319 | struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; | ||
320 | struct hd_geometry g; | ||
321 | sector_t capacity; | ||
322 | |||
323 | if (cmd == CDROMEJECT) { | ||
324 | if (pf->access == 1) { | ||
325 | pf_eject(pf); | ||
326 | return 0; | ||
327 | } | ||
328 | return -EBUSY; | ||
329 | } | ||
330 | if (cmd != HDIO_GETGEO) | ||
331 | return -EINVAL; | ||
332 | capacity = get_capacity(pf->disk); | ||
333 | if (capacity < PF_FD_MAX) { | ||
334 | g.cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT); | ||
335 | g.heads = PF_FD_HDS; | ||
336 | g.sectors = PF_FD_SPT; | ||
337 | } else { | ||
338 | g.cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT); | ||
339 | g.heads = PF_HD_HDS; | ||
340 | g.sectors = PF_HD_SPT; | ||
341 | } | ||
342 | if (copy_to_user(geo, &g, sizeof(g))) | ||
343 | return -EFAULT; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int pf_release(struct inode *inode, struct file *file) | ||
348 | { | ||
349 | struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; | ||
350 | |||
351 | if (pf->access <= 0) | ||
352 | return -EINVAL; | ||
353 | |||
354 | pf->access--; | ||
355 | |||
356 | if (!pf->access && pf->removable) | ||
357 | pf_lock(pf, 0); | ||
358 | |||
359 | return 0; | ||
360 | |||
361 | } | ||
362 | |||
363 | static int pf_check_media(struct gendisk *disk) | ||
364 | { | ||
365 | return 1; | ||
366 | } | ||
367 | |||
368 | static inline int status_reg(struct pf_unit *pf) | ||
369 | { | ||
370 | return pi_read_regr(pf->pi, 1, 6); | ||
371 | } | ||
372 | |||
373 | static inline int read_reg(struct pf_unit *pf, int reg) | ||
374 | { | ||
375 | return pi_read_regr(pf->pi, 0, reg); | ||
376 | } | ||
377 | |||
378 | static inline void write_reg(struct pf_unit *pf, int reg, int val) | ||
379 | { | ||
380 | pi_write_regr(pf->pi, 0, reg, val); | ||
381 | } | ||
382 | |||
383 | static int pf_wait(struct pf_unit *pf, int go, int stop, char *fun, char *msg) | ||
384 | { | ||
385 | int j, r, e, s, p; | ||
386 | |||
387 | j = 0; | ||
388 | while ((((r = status_reg(pf)) & go) || (stop && (!(r & stop)))) | ||
389 | && (j++ < PF_SPIN)) | ||
390 | udelay(PF_SPIN_DEL); | ||
391 | |||
392 | if ((r & (STAT_ERR & stop)) || (j >= PF_SPIN)) { | ||
393 | s = read_reg(pf, 7); | ||
394 | e = read_reg(pf, 1); | ||
395 | p = read_reg(pf, 2); | ||
396 | if (j >= PF_SPIN) | ||
397 | e |= 0x100; | ||
398 | if (fun) | ||
399 | printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x" | ||
400 | " loop=%d phase=%d\n", | ||
401 | pf->name, fun, msg, r, s, e, j, p); | ||
402 | return (e << 8) + s; | ||
403 | } | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int pf_command(struct pf_unit *pf, char *cmd, int dlen, char *fun) | ||
408 | { | ||
409 | pi_connect(pf->pi); | ||
410 | |||
411 | write_reg(pf, 6, 0xa0+0x10*pf->drive); | ||
412 | |||
413 | if (pf_wait(pf, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) { | ||
414 | pi_disconnect(pf->pi); | ||
415 | return -1; | ||
416 | } | ||
417 | |||
418 | write_reg(pf, 4, dlen % 256); | ||
419 | write_reg(pf, 5, dlen / 256); | ||
420 | write_reg(pf, 7, 0xa0); /* ATAPI packet command */ | ||
421 | |||
422 | if (pf_wait(pf, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) { | ||
423 | pi_disconnect(pf->pi); | ||
424 | return -1; | ||
425 | } | ||
426 | |||
427 | if (read_reg(pf, 2) != 1) { | ||
428 | printk("%s: %s: command phase error\n", pf->name, fun); | ||
429 | pi_disconnect(pf->pi); | ||
430 | return -1; | ||
431 | } | ||
432 | |||
433 | pi_write_block(pf->pi, cmd, 12); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int pf_completion(struct pf_unit *pf, char *buf, char *fun) | ||
439 | { | ||
440 | int r, s, n; | ||
441 | |||
442 | r = pf_wait(pf, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR, | ||
443 | fun, "completion"); | ||
444 | |||
445 | if ((read_reg(pf, 2) & 2) && (read_reg(pf, 7) & STAT_DRQ)) { | ||
446 | n = (((read_reg(pf, 4) + 256 * read_reg(pf, 5)) + | ||
447 | 3) & 0xfffc); | ||
448 | pi_read_block(pf->pi, buf, n); | ||
449 | } | ||
450 | |||
451 | s = pf_wait(pf, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done"); | ||
452 | |||
453 | pi_disconnect(pf->pi); | ||
454 | |||
455 | return (r ? r : s); | ||
456 | } | ||
457 | |||
458 | static void pf_req_sense(struct pf_unit *pf, int quiet) | ||
459 | { | ||
460 | char rs_cmd[12] = | ||
461 | { ATAPI_REQ_SENSE, pf->lun << 5, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 }; | ||
462 | char buf[16]; | ||
463 | int r; | ||
464 | |||
465 | r = pf_command(pf, rs_cmd, 16, "Request sense"); | ||
466 | mdelay(1); | ||
467 | if (!r) | ||
468 | pf_completion(pf, buf, "Request sense"); | ||
469 | |||
470 | if ((!r) && (!quiet)) | ||
471 | printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n", | ||
472 | pf->name, buf[2] & 0xf, buf[12], buf[13]); | ||
473 | } | ||
474 | |||
475 | static int pf_atapi(struct pf_unit *pf, char *cmd, int dlen, char *buf, char *fun) | ||
476 | { | ||
477 | int r; | ||
478 | |||
479 | r = pf_command(pf, cmd, dlen, fun); | ||
480 | mdelay(1); | ||
481 | if (!r) | ||
482 | r = pf_completion(pf, buf, fun); | ||
483 | if (r) | ||
484 | pf_req_sense(pf, !fun); | ||
485 | |||
486 | return r; | ||
487 | } | ||
488 | |||
489 | #define DBMSG(msg) ((verbose>1)?(msg):NULL) | ||
490 | |||
491 | static void pf_lock(struct pf_unit *pf, int func) | ||
492 | { | ||
493 | char lo_cmd[12] = { ATAPI_LOCK, pf->lun << 5, 0, 0, func, 0, 0, 0, 0, 0, 0, 0 }; | ||
494 | |||
495 | pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "unlock" : "lock"); | ||
496 | } | ||
497 | |||
498 | static void pf_eject(struct pf_unit *pf) | ||
499 | { | ||
500 | char ej_cmd[12] = { ATAPI_DOOR, pf->lun << 5, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; | ||
501 | |||
502 | pf_lock(pf, 0); | ||
503 | pf_atapi(pf, ej_cmd, 0, pf_scratch, "eject"); | ||
504 | } | ||
505 | |||
506 | #define PF_RESET_TMO 30 /* in tenths of a second */ | ||
507 | |||
508 | static void pf_sleep(int cs) | ||
509 | { | ||
510 | current->state = TASK_INTERRUPTIBLE; | ||
511 | schedule_timeout(cs); | ||
512 | } | ||
513 | |||
514 | /* the ATAPI standard actually specifies the contents of all 7 registers | ||
515 | after a reset, but the specification is ambiguous concerning the last | ||
516 | two bytes, and different drives interpret the standard differently. | ||
517 | */ | ||
518 | |||
519 | static int pf_reset(struct pf_unit *pf) | ||
520 | { | ||
521 | int i, k, flg; | ||
522 | int expect[5] = { 1, 1, 1, 0x14, 0xeb }; | ||
523 | |||
524 | pi_connect(pf->pi); | ||
525 | write_reg(pf, 6, 0xa0+0x10*pf->drive); | ||
526 | write_reg(pf, 7, 8); | ||
527 | |||
528 | pf_sleep(20 * HZ / 1000); | ||
529 | |||
530 | k = 0; | ||
531 | while ((k++ < PF_RESET_TMO) && (status_reg(pf) & STAT_BUSY)) | ||
532 | pf_sleep(HZ / 10); | ||
533 | |||
534 | flg = 1; | ||
535 | for (i = 0; i < 5; i++) | ||
536 | flg &= (read_reg(pf, i + 1) == expect[i]); | ||
537 | |||
538 | if (verbose) { | ||
539 | printk("%s: Reset (%d) signature = ", pf->name, k); | ||
540 | for (i = 0; i < 5; i++) | ||
541 | printk("%3x", read_reg(pf, i + 1)); | ||
542 | if (!flg) | ||
543 | printk(" (incorrect)"); | ||
544 | printk("\n"); | ||
545 | } | ||
546 | |||
547 | pi_disconnect(pf->pi); | ||
548 | return flg - 1; | ||
549 | } | ||
550 | |||
551 | static void pf_mode_sense(struct pf_unit *pf) | ||
552 | { | ||
553 | char ms_cmd[12] = | ||
554 | { ATAPI_MODE_SENSE, pf->lun << 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 }; | ||
555 | char buf[8]; | ||
556 | |||
557 | pf_atapi(pf, ms_cmd, 8, buf, DBMSG("mode sense")); | ||
558 | pf->media_status = PF_RW; | ||
559 | if (buf[3] & 0x80) | ||
560 | pf->media_status = PF_RO; | ||
561 | } | ||
562 | |||
563 | static void xs(char *buf, char *targ, int offs, int len) | ||
564 | { | ||
565 | int j, k, l; | ||
566 | |||
567 | j = 0; | ||
568 | l = 0; | ||
569 | for (k = 0; k < len; k++) | ||
570 | if ((buf[k + offs] != 0x20) || (buf[k + offs] != l)) | ||
571 | l = targ[j++] = buf[k + offs]; | ||
572 | if (l == 0x20) | ||
573 | j--; | ||
574 | targ[j] = 0; | ||
575 | } | ||
576 | |||
577 | static int xl(char *buf, int offs) | ||
578 | { | ||
579 | int v, k; | ||
580 | |||
581 | v = 0; | ||
582 | for (k = 0; k < 4; k++) | ||
583 | v = v * 256 + (buf[k + offs] & 0xff); | ||
584 | return v; | ||
585 | } | ||
586 | |||
587 | static void pf_get_capacity(struct pf_unit *pf) | ||
588 | { | ||
589 | char rc_cmd[12] = { ATAPI_CAPACITY, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
590 | char buf[8]; | ||
591 | int bs; | ||
592 | |||
593 | if (pf_atapi(pf, rc_cmd, 8, buf, DBMSG("get capacity"))) { | ||
594 | pf->media_status = PF_NM; | ||
595 | return; | ||
596 | } | ||
597 | set_capacity(pf->disk, xl(buf, 0) + 1); | ||
598 | bs = xl(buf, 4); | ||
599 | if (bs != 512) { | ||
600 | set_capacity(pf->disk, 0); | ||
601 | if (verbose) | ||
602 | printk("%s: Drive %d, LUN %d," | ||
603 | " unsupported block size %d\n", | ||
604 | pf->name, pf->drive, pf->lun, bs); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static int pf_identify(struct pf_unit *pf) | ||
609 | { | ||
610 | int dt, s; | ||
611 | char *ms[2] = { "master", "slave" }; | ||
612 | char mf[10], id[18]; | ||
613 | char id_cmd[12] = | ||
614 | { ATAPI_IDENTIFY, pf->lun << 5, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; | ||
615 | char buf[36]; | ||
616 | |||
617 | s = pf_atapi(pf, id_cmd, 36, buf, "identify"); | ||
618 | if (s) | ||
619 | return -1; | ||
620 | |||
621 | dt = buf[0] & 0x1f; | ||
622 | if ((dt != 0) && (dt != 7)) { | ||
623 | if (verbose) | ||
624 | printk("%s: Drive %d, LUN %d, unsupported type %d\n", | ||
625 | pf->name, pf->drive, pf->lun, dt); | ||
626 | return -1; | ||
627 | } | ||
628 | |||
629 | xs(buf, mf, 8, 8); | ||
630 | xs(buf, id, 16, 16); | ||
631 | |||
632 | pf->removable = (buf[1] & 0x80); | ||
633 | |||
634 | pf_mode_sense(pf); | ||
635 | pf_mode_sense(pf); | ||
636 | pf_mode_sense(pf); | ||
637 | |||
638 | pf_get_capacity(pf); | ||
639 | |||
640 | printk("%s: %s %s, %s LUN %d, type %d", | ||
641 | pf->name, mf, id, ms[pf->drive], pf->lun, dt); | ||
642 | if (pf->removable) | ||
643 | printk(", removable"); | ||
644 | if (pf->media_status == PF_NM) | ||
645 | printk(", no media\n"); | ||
646 | else { | ||
647 | if (pf->media_status == PF_RO) | ||
648 | printk(", RO"); | ||
649 | printk(", %llu blocks\n", | ||
650 | (unsigned long long)get_capacity(pf->disk)); | ||
651 | } | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | /* returns 0, with id set if drive is detected | ||
656 | -1, if drive detection failed | ||
657 | */ | ||
658 | static int pf_probe(struct pf_unit *pf) | ||
659 | { | ||
660 | if (pf->drive == -1) { | ||
661 | for (pf->drive = 0; pf->drive <= 1; pf->drive++) | ||
662 | if (!pf_reset(pf)) { | ||
663 | if (pf->lun != -1) | ||
664 | return pf_identify(pf); | ||
665 | else | ||
666 | for (pf->lun = 0; pf->lun < 8; pf->lun++) | ||
667 | if (!pf_identify(pf)) | ||
668 | return 0; | ||
669 | } | ||
670 | } else { | ||
671 | if (pf_reset(pf)) | ||
672 | return -1; | ||
673 | if (pf->lun != -1) | ||
674 | return pf_identify(pf); | ||
675 | for (pf->lun = 0; pf->lun < 8; pf->lun++) | ||
676 | if (!pf_identify(pf)) | ||
677 | return 0; | ||
678 | } | ||
679 | return -1; | ||
680 | } | ||
681 | |||
682 | static int pf_detect(void) | ||
683 | { | ||
684 | struct pf_unit *pf = units; | ||
685 | int k, unit; | ||
686 | |||
687 | printk("%s: %s version %s, major %d, cluster %d, nice %d\n", | ||
688 | name, name, PF_VERSION, major, cluster, nice); | ||
689 | |||
690 | k = 0; | ||
691 | if (pf_drive_count == 0) { | ||
692 | if (pi_init(pf->pi, 1, -1, -1, -1, -1, -1, pf_scratch, PI_PF, | ||
693 | verbose, pf->name)) { | ||
694 | if (!pf_probe(pf) && pf->disk) { | ||
695 | pf->present = 1; | ||
696 | k++; | ||
697 | } else | ||
698 | pi_release(pf->pi); | ||
699 | } | ||
700 | |||
701 | } else | ||
702 | for (unit = 0; unit < PF_UNITS; unit++, pf++) { | ||
703 | int *conf = *drives[unit]; | ||
704 | if (!conf[D_PRT]) | ||
705 | continue; | ||
706 | if (pi_init(pf->pi, 0, conf[D_PRT], conf[D_MOD], | ||
707 | conf[D_UNI], conf[D_PRO], conf[D_DLY], | ||
708 | pf_scratch, PI_PF, verbose, pf->name)) { | ||
709 | if (!pf_probe(pf) && pf->disk) { | ||
710 | pf->present = 1; | ||
711 | k++; | ||
712 | } else | ||
713 | pi_release(pf->pi); | ||
714 | } | ||
715 | } | ||
716 | if (k) | ||
717 | return 0; | ||
718 | |||
719 | printk("%s: No ATAPI disk detected\n", name); | ||
720 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) | ||
721 | put_disk(pf->disk); | ||
722 | return -1; | ||
723 | } | ||
724 | |||
725 | /* The i/o request engine */ | ||
726 | |||
727 | static int pf_start(struct pf_unit *pf, int cmd, int b, int c) | ||
728 | { | ||
729 | int i; | ||
730 | char io_cmd[12] = { cmd, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
731 | |||
732 | for (i = 0; i < 4; i++) { | ||
733 | io_cmd[5 - i] = b & 0xff; | ||
734 | b = b >> 8; | ||
735 | } | ||
736 | |||
737 | io_cmd[8] = c & 0xff; | ||
738 | io_cmd[7] = (c >> 8) & 0xff; | ||
739 | |||
740 | i = pf_command(pf, io_cmd, c * 512, "start i/o"); | ||
741 | |||
742 | mdelay(1); | ||
743 | |||
744 | return i; | ||
745 | } | ||
746 | |||
747 | static int pf_ready(void) | ||
748 | { | ||
749 | return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask)); | ||
750 | } | ||
751 | |||
752 | static struct request_queue *pf_queue; | ||
753 | |||
754 | static void do_pf_request(request_queue_t * q) | ||
755 | { | ||
756 | if (pf_busy) | ||
757 | return; | ||
758 | repeat: | ||
759 | pf_req = elv_next_request(q); | ||
760 | if (!pf_req) | ||
761 | return; | ||
762 | |||
763 | pf_current = pf_req->rq_disk->private_data; | ||
764 | pf_block = pf_req->sector; | ||
765 | pf_run = pf_req->nr_sectors; | ||
766 | pf_count = pf_req->current_nr_sectors; | ||
767 | |||
768 | if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { | ||
769 | end_request(pf_req, 0); | ||
770 | goto repeat; | ||
771 | } | ||
772 | |||
773 | pf_cmd = rq_data_dir(pf_req); | ||
774 | pf_buf = pf_req->buffer; | ||
775 | pf_retries = 0; | ||
776 | |||
777 | pf_busy = 1; | ||
778 | if (pf_cmd == READ) | ||
779 | pi_do_claimed(pf_current->pi, do_pf_read); | ||
780 | else if (pf_cmd == WRITE) | ||
781 | pi_do_claimed(pf_current->pi, do_pf_write); | ||
782 | else { | ||
783 | pf_busy = 0; | ||
784 | end_request(pf_req, 0); | ||
785 | goto repeat; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | static int pf_next_buf(void) | ||
790 | { | ||
791 | unsigned long saved_flags; | ||
792 | |||
793 | pf_count--; | ||
794 | pf_run--; | ||
795 | pf_buf += 512; | ||
796 | pf_block++; | ||
797 | if (!pf_run) | ||
798 | return 0; | ||
799 | if (!pf_count) | ||
800 | return 1; | ||
801 | spin_lock_irqsave(&pf_spin_lock, saved_flags); | ||
802 | end_request(pf_req, 1); | ||
803 | pf_count = pf_req->current_nr_sectors; | ||
804 | pf_buf = pf_req->buffer; | ||
805 | spin_unlock_irqrestore(&pf_spin_lock, saved_flags); | ||
806 | return 1; | ||
807 | } | ||
808 | |||
809 | static inline void next_request(int success) | ||
810 | { | ||
811 | unsigned long saved_flags; | ||
812 | |||
813 | spin_lock_irqsave(&pf_spin_lock, saved_flags); | ||
814 | end_request(pf_req, success); | ||
815 | pf_busy = 0; | ||
816 | do_pf_request(pf_queue); | ||
817 | spin_unlock_irqrestore(&pf_spin_lock, saved_flags); | ||
818 | } | ||
819 | |||
820 | /* detach from the calling context - in case the spinlock is held */ | ||
821 | static void do_pf_read(void) | ||
822 | { | ||
823 | ps_set_intr(do_pf_read_start, NULL, 0, nice); | ||
824 | } | ||
825 | |||
826 | static void do_pf_read_start(void) | ||
827 | { | ||
828 | pf_busy = 1; | ||
829 | |||
830 | if (pf_start(pf_current, ATAPI_READ_10, pf_block, pf_run)) { | ||
831 | pi_disconnect(pf_current->pi); | ||
832 | if (pf_retries < PF_MAX_RETRIES) { | ||
833 | pf_retries++; | ||
834 | pi_do_claimed(pf_current->pi, do_pf_read_start); | ||
835 | return; | ||
836 | } | ||
837 | next_request(0); | ||
838 | return; | ||
839 | } | ||
840 | pf_mask = STAT_DRQ; | ||
841 | ps_set_intr(do_pf_read_drq, pf_ready, PF_TMO, nice); | ||
842 | } | ||
843 | |||
844 | static void do_pf_read_drq(void) | ||
845 | { | ||
846 | while (1) { | ||
847 | if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, | ||
848 | "read block", "completion") & STAT_ERR) { | ||
849 | pi_disconnect(pf_current->pi); | ||
850 | if (pf_retries < PF_MAX_RETRIES) { | ||
851 | pf_req_sense(pf_current, 0); | ||
852 | pf_retries++; | ||
853 | pi_do_claimed(pf_current->pi, do_pf_read_start); | ||
854 | return; | ||
855 | } | ||
856 | next_request(0); | ||
857 | return; | ||
858 | } | ||
859 | pi_read_block(pf_current->pi, pf_buf, 512); | ||
860 | if (pf_next_buf()) | ||
861 | break; | ||
862 | } | ||
863 | pi_disconnect(pf_current->pi); | ||
864 | next_request(1); | ||
865 | } | ||
866 | |||
867 | static void do_pf_write(void) | ||
868 | { | ||
869 | ps_set_intr(do_pf_write_start, NULL, 0, nice); | ||
870 | } | ||
871 | |||
872 | static void do_pf_write_start(void) | ||
873 | { | ||
874 | pf_busy = 1; | ||
875 | |||
876 | if (pf_start(pf_current, ATAPI_WRITE_10, pf_block, pf_run)) { | ||
877 | pi_disconnect(pf_current->pi); | ||
878 | if (pf_retries < PF_MAX_RETRIES) { | ||
879 | pf_retries++; | ||
880 | pi_do_claimed(pf_current->pi, do_pf_write_start); | ||
881 | return; | ||
882 | } | ||
883 | next_request(0); | ||
884 | return; | ||
885 | } | ||
886 | |||
887 | while (1) { | ||
888 | if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, | ||
889 | "write block", "data wait") & STAT_ERR) { | ||
890 | pi_disconnect(pf_current->pi); | ||
891 | if (pf_retries < PF_MAX_RETRIES) { | ||
892 | pf_retries++; | ||
893 | pi_do_claimed(pf_current->pi, do_pf_write_start); | ||
894 | return; | ||
895 | } | ||
896 | next_request(0); | ||
897 | return; | ||
898 | } | ||
899 | pi_write_block(pf_current->pi, pf_buf, 512); | ||
900 | if (pf_next_buf()) | ||
901 | break; | ||
902 | } | ||
903 | pf_mask = 0; | ||
904 | ps_set_intr(do_pf_write_done, pf_ready, PF_TMO, nice); | ||
905 | } | ||
906 | |||
907 | static void do_pf_write_done(void) | ||
908 | { | ||
909 | if (pf_wait(pf_current, STAT_BUSY, 0, "write block", "done") & STAT_ERR) { | ||
910 | pi_disconnect(pf_current->pi); | ||
911 | if (pf_retries < PF_MAX_RETRIES) { | ||
912 | pf_retries++; | ||
913 | pi_do_claimed(pf_current->pi, do_pf_write_start); | ||
914 | return; | ||
915 | } | ||
916 | next_request(0); | ||
917 | return; | ||
918 | } | ||
919 | pi_disconnect(pf_current->pi); | ||
920 | next_request(1); | ||
921 | } | ||
922 | |||
923 | static int __init pf_init(void) | ||
924 | { /* preliminary initialisation */ | ||
925 | struct pf_unit *pf; | ||
926 | int unit; | ||
927 | |||
928 | if (disable) | ||
929 | return -1; | ||
930 | |||
931 | pf_init_units(); | ||
932 | |||
933 | if (pf_detect()) | ||
934 | return -1; | ||
935 | pf_busy = 0; | ||
936 | |||
937 | if (register_blkdev(major, name)) { | ||
938 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) | ||
939 | put_disk(pf->disk); | ||
940 | return -1; | ||
941 | } | ||
942 | pf_queue = blk_init_queue(do_pf_request, &pf_spin_lock); | ||
943 | if (!pf_queue) { | ||
944 | unregister_blkdev(major, name); | ||
945 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) | ||
946 | put_disk(pf->disk); | ||
947 | return -1; | ||
948 | } | ||
949 | |||
950 | blk_queue_max_phys_segments(pf_queue, cluster); | ||
951 | blk_queue_max_hw_segments(pf_queue, cluster); | ||
952 | |||
953 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { | ||
954 | struct gendisk *disk = pf->disk; | ||
955 | |||
956 | if (!pf->present) | ||
957 | continue; | ||
958 | disk->private_data = pf; | ||
959 | disk->queue = pf_queue; | ||
960 | add_disk(disk); | ||
961 | } | ||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | static void __exit pf_exit(void) | ||
966 | { | ||
967 | struct pf_unit *pf; | ||
968 | int unit; | ||
969 | unregister_blkdev(major, name); | ||
970 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { | ||
971 | if (!pf->present) | ||
972 | continue; | ||
973 | del_gendisk(pf->disk); | ||
974 | put_disk(pf->disk); | ||
975 | pi_release(pf->pi); | ||
976 | } | ||
977 | blk_cleanup_queue(pf_queue); | ||
978 | } | ||
979 | |||
980 | MODULE_LICENSE("GPL"); | ||
981 | module_init(pf_init) | ||
982 | module_exit(pf_exit) | ||
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c new file mode 100644 index 000000000000..dbeb107bb971 --- /dev/null +++ b/drivers/block/paride/pg.c | |||
@@ -0,0 +1,723 @@ | |||
1 | /* | ||
2 | pg.c (c) 1998 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | The pg driver provides a simple character device interface for | ||
6 | sending ATAPI commands to a device. With the exception of the | ||
7 | ATAPI reset operation, all operations are performed by a pair | ||
8 | of read and write operations to the appropriate /dev/pgN device. | ||
9 | A write operation delivers a command and any outbound data in | ||
10 | a single buffer. Normally, the write will succeed unless the | ||
11 | device is offline or malfunctioning, or there is already another | ||
12 | command pending. If the write succeeds, it should be followed | ||
13 | immediately by a read operation, to obtain any returned data and | ||
14 | status information. A read will fail if there is no operation | ||
15 | in progress. | ||
16 | |||
17 | As a special case, the device can be reset with a write operation, | ||
18 | and in this case, no following read is expected, or permitted. | ||
19 | |||
20 | There are no ioctl() operations. Any single operation | ||
21 | may transfer at most PG_MAX_DATA bytes. Note that the driver must | ||
22 | copy the data through an internal buffer. In keeping with all | ||
23 | current ATAPI devices, command packets are assumed to be exactly | ||
24 | 12 bytes in length. | ||
25 | |||
26 | To permit future changes to this interface, the headers in the | ||
27 | read and write buffers contain a single character "magic" flag. | ||
28 | Currently this flag must be the character "P". | ||
29 | |||
30 | By default, the driver will autoprobe for a single parallel | ||
31 | port ATAPI device, but if their individual parameters are | ||
32 | specified, the driver can handle up to 4 devices. | ||
33 | |||
34 | To use this device, you must have the following device | ||
35 | special files defined: | ||
36 | |||
37 | /dev/pg0 c 97 0 | ||
38 | /dev/pg1 c 97 1 | ||
39 | /dev/pg2 c 97 2 | ||
40 | /dev/pg3 c 97 3 | ||
41 | |||
42 | (You'll need to change the 97 to something else if you use | ||
43 | the 'major' parameter to install the driver on a different | ||
44 | major number.) | ||
45 | |||
46 | The behaviour of the pg driver can be altered by setting | ||
47 | some parameters from the insmod command line. The following | ||
48 | parameters are adjustable: | ||
49 | |||
50 | drive0 These four arguments can be arrays of | ||
51 | drive1 1-6 integers as follows: | ||
52 | drive2 | ||
53 | drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly> | ||
54 | |||
55 | Where, | ||
56 | |||
57 | <prt> is the base of the parallel port address for | ||
58 | the corresponding drive. (required) | ||
59 | |||
60 | <pro> is the protocol number for the adapter that | ||
61 | supports this drive. These numbers are | ||
62 | logged by 'paride' when the protocol modules | ||
63 | are initialised. (0 if not given) | ||
64 | |||
65 | <uni> for those adapters that support chained | ||
66 | devices, this is the unit selector for the | ||
67 | chain of devices on the given port. It should | ||
68 | be zero for devices that don't support chaining. | ||
69 | (0 if not given) | ||
70 | |||
71 | <mod> this can be -1 to choose the best mode, or one | ||
72 | of the mode numbers supported by the adapter. | ||
73 | (-1 if not given) | ||
74 | |||
75 | <slv> ATAPI devices can be jumpered to master or slave. | ||
76 | Set this to 0 to choose the master drive, 1 to | ||
77 | choose the slave, -1 (the default) to choose the | ||
78 | first drive found. | ||
79 | |||
80 | <dly> some parallel ports require the driver to | ||
81 | go more slowly. -1 sets a default value that | ||
82 | should work with the chosen protocol. Otherwise, | ||
83 | set this to a small integer, the larger it is | ||
84 | the slower the port i/o. In some cases, setting | ||
85 | this to zero will speed up the device. (default -1) | ||
86 | |||
87 | major You may use this parameter to overide the | ||
88 | default major number (97) that this driver | ||
89 | will use. Be sure to change the device | ||
90 | name as well. | ||
91 | |||
92 | name This parameter is a character string that | ||
93 | contains the name the kernel will use for this | ||
94 | device (in /proc output, for instance). | ||
95 | (default "pg"). | ||
96 | |||
97 | verbose This parameter controls the amount of logging | ||
98 | that is done by the driver. Set it to 0 for | ||
99 | quiet operation, to 1 to enable progress | ||
100 | messages while the driver probes for devices, | ||
101 | or to 2 for full debug logging. (default 0) | ||
102 | |||
103 | If this driver is built into the kernel, you can use | ||
104 | the following command line parameters, with the same values | ||
105 | as the corresponding module parameters listed above: | ||
106 | |||
107 | pg.drive0 | ||
108 | pg.drive1 | ||
109 | pg.drive2 | ||
110 | pg.drive3 | ||
111 | |||
112 | In addition, you can use the parameter pg.disable to disable | ||
113 | the driver entirely. | ||
114 | |||
115 | */ | ||
116 | |||
117 | /* Changes: | ||
118 | |||
119 | 1.01 GRG 1998.06.16 Bug fixes | ||
120 | 1.02 GRG 1998.09.24 Added jumbo support | ||
121 | |||
122 | */ | ||
123 | |||
124 | #define PG_VERSION "1.02" | ||
125 | #define PG_MAJOR 97 | ||
126 | #define PG_NAME "pg" | ||
127 | #define PG_UNITS 4 | ||
128 | |||
129 | #ifndef PI_PG | ||
130 | #define PI_PG 4 | ||
131 | #endif | ||
132 | |||
133 | /* Here are things one can override from the insmod command. | ||
134 | Most are autoprobed by paride unless set here. Verbose is 0 | ||
135 | by default. | ||
136 | |||
137 | */ | ||
138 | |||
139 | static int verbose = 0; | ||
140 | static int major = PG_MAJOR; | ||
141 | static char *name = PG_NAME; | ||
142 | static int disable = 0; | ||
143 | |||
144 | static int drive0[6] = { 0, 0, 0, -1, -1, -1 }; | ||
145 | static int drive1[6] = { 0, 0, 0, -1, -1, -1 }; | ||
146 | static int drive2[6] = { 0, 0, 0, -1, -1, -1 }; | ||
147 | static int drive3[6] = { 0, 0, 0, -1, -1, -1 }; | ||
148 | |||
149 | static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; | ||
150 | static int pg_drive_count; | ||
151 | |||
152 | enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; | ||
153 | |||
154 | /* end of parameters */ | ||
155 | |||
156 | #include <linux/module.h> | ||
157 | #include <linux/init.h> | ||
158 | #include <linux/fs.h> | ||
159 | #include <linux/devfs_fs_kernel.h> | ||
160 | #include <linux/delay.h> | ||
161 | #include <linux/slab.h> | ||
162 | #include <linux/mtio.h> | ||
163 | #include <linux/pg.h> | ||
164 | #include <linux/device.h> | ||
165 | |||
166 | #include <asm/uaccess.h> | ||
167 | |||
168 | module_param(verbose, bool, 0644); | ||
169 | module_param(major, int, 0); | ||
170 | module_param(name, charp, 0); | ||
171 | module_param_array(drive0, int, NULL, 0); | ||
172 | module_param_array(drive1, int, NULL, 0); | ||
173 | module_param_array(drive2, int, NULL, 0); | ||
174 | module_param_array(drive3, int, NULL, 0); | ||
175 | |||
176 | #include "paride.h" | ||
177 | |||
178 | #define PG_SPIN_DEL 50 /* spin delay in micro-seconds */ | ||
179 | #define PG_SPIN 200 | ||
180 | #define PG_TMO HZ | ||
181 | #define PG_RESET_TMO 10*HZ | ||
182 | |||
183 | #define STAT_ERR 0x01 | ||
184 | #define STAT_INDEX 0x02 | ||
185 | #define STAT_ECC 0x04 | ||
186 | #define STAT_DRQ 0x08 | ||
187 | #define STAT_SEEK 0x10 | ||
188 | #define STAT_WRERR 0x20 | ||
189 | #define STAT_READY 0x40 | ||
190 | #define STAT_BUSY 0x80 | ||
191 | |||
192 | #define ATAPI_IDENTIFY 0x12 | ||
193 | |||
194 | static int pg_open(struct inode *inode, struct file *file); | ||
195 | static int pg_release(struct inode *inode, struct file *file); | ||
196 | static ssize_t pg_read(struct file *filp, char __user *buf, | ||
197 | size_t count, loff_t * ppos); | ||
198 | static ssize_t pg_write(struct file *filp, const char __user *buf, | ||
199 | size_t count, loff_t * ppos); | ||
200 | static int pg_detect(void); | ||
201 | |||
202 | #define PG_NAMELEN 8 | ||
203 | |||
204 | struct pg { | ||
205 | struct pi_adapter pia; /* interface to paride layer */ | ||
206 | struct pi_adapter *pi; | ||
207 | int busy; /* write done, read expected */ | ||
208 | int start; /* jiffies at command start */ | ||
209 | int dlen; /* transfer size requested */ | ||
210 | unsigned long timeout; /* timeout requested */ | ||
211 | int status; /* last sense key */ | ||
212 | int drive; /* drive */ | ||
213 | unsigned long access; /* count of active opens ... */ | ||
214 | int present; /* device present ? */ | ||
215 | char *bufptr; | ||
216 | char name[PG_NAMELEN]; /* pg0, pg1, ... */ | ||
217 | }; | ||
218 | |||
219 | static struct pg devices[PG_UNITS]; | ||
220 | |||
221 | static int pg_identify(struct pg *dev, int log); | ||
222 | |||
223 | static char pg_scratch[512]; /* scratch block buffer */ | ||
224 | |||
225 | static struct class_simple *pg_class; | ||
226 | |||
227 | /* kernel glue structures */ | ||
228 | |||
229 | static struct file_operations pg_fops = { | ||
230 | .owner = THIS_MODULE, | ||
231 | .read = pg_read, | ||
232 | .write = pg_write, | ||
233 | .open = pg_open, | ||
234 | .release = pg_release, | ||
235 | }; | ||
236 | |||
237 | static void pg_init_units(void) | ||
238 | { | ||
239 | int unit; | ||
240 | |||
241 | pg_drive_count = 0; | ||
242 | for (unit = 0; unit < PG_UNITS; unit++) { | ||
243 | int *parm = *drives[unit]; | ||
244 | struct pg *dev = &devices[unit]; | ||
245 | dev->pi = &dev->pia; | ||
246 | clear_bit(0, &dev->access); | ||
247 | dev->busy = 0; | ||
248 | dev->present = 0; | ||
249 | dev->bufptr = NULL; | ||
250 | dev->drive = parm[D_SLV]; | ||
251 | snprintf(dev->name, PG_NAMELEN, "%s%c", name, 'a'+unit); | ||
252 | if (parm[D_PRT]) | ||
253 | pg_drive_count++; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | static inline int status_reg(struct pg *dev) | ||
258 | { | ||
259 | return pi_read_regr(dev->pi, 1, 6); | ||
260 | } | ||
261 | |||
262 | static inline int read_reg(struct pg *dev, int reg) | ||
263 | { | ||
264 | return pi_read_regr(dev->pi, 0, reg); | ||
265 | } | ||
266 | |||
267 | static inline void write_reg(struct pg *dev, int reg, int val) | ||
268 | { | ||
269 | pi_write_regr(dev->pi, 0, reg, val); | ||
270 | } | ||
271 | |||
272 | static inline u8 DRIVE(struct pg *dev) | ||
273 | { | ||
274 | return 0xa0+0x10*dev->drive; | ||
275 | } | ||
276 | |||
277 | static void pg_sleep(int cs) | ||
278 | { | ||
279 | current->state = TASK_INTERRUPTIBLE; | ||
280 | schedule_timeout(cs); | ||
281 | } | ||
282 | |||
283 | static int pg_wait(struct pg *dev, int go, int stop, unsigned long tmo, char *msg) | ||
284 | { | ||
285 | int j, r, e, s, p, to; | ||
286 | |||
287 | dev->status = 0; | ||
288 | |||
289 | j = 0; | ||
290 | while ((((r = status_reg(dev)) & go) || (stop && (!(r & stop)))) | ||
291 | && time_before(jiffies, tmo)) { | ||
292 | if (j++ < PG_SPIN) | ||
293 | udelay(PG_SPIN_DEL); | ||
294 | else | ||
295 | pg_sleep(1); | ||
296 | } | ||
297 | |||
298 | to = time_after_eq(jiffies, tmo); | ||
299 | |||
300 | if ((r & (STAT_ERR & stop)) || to) { | ||
301 | s = read_reg(dev, 7); | ||
302 | e = read_reg(dev, 1); | ||
303 | p = read_reg(dev, 2); | ||
304 | if (verbose > 1) | ||
305 | printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n", | ||
306 | dev->name, msg, s, e, p, to ? " timeout" : ""); | ||
307 | if (to) | ||
308 | e |= 0x100; | ||
309 | dev->status = (e >> 4) & 0xff; | ||
310 | return -1; | ||
311 | } | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int pg_command(struct pg *dev, char *cmd, int dlen, unsigned long tmo) | ||
316 | { | ||
317 | int k; | ||
318 | |||
319 | pi_connect(dev->pi); | ||
320 | |||
321 | write_reg(dev, 6, DRIVE(dev)); | ||
322 | |||
323 | if (pg_wait(dev, STAT_BUSY | STAT_DRQ, 0, tmo, "before command")) | ||
324 | goto fail; | ||
325 | |||
326 | write_reg(dev, 4, dlen % 256); | ||
327 | write_reg(dev, 5, dlen / 256); | ||
328 | write_reg(dev, 7, 0xa0); /* ATAPI packet command */ | ||
329 | |||
330 | if (pg_wait(dev, STAT_BUSY, STAT_DRQ, tmo, "command DRQ")) | ||
331 | goto fail; | ||
332 | |||
333 | if (read_reg(dev, 2) != 1) { | ||
334 | printk("%s: command phase error\n", dev->name); | ||
335 | goto fail; | ||
336 | } | ||
337 | |||
338 | pi_write_block(dev->pi, cmd, 12); | ||
339 | |||
340 | if (verbose > 1) { | ||
341 | printk("%s: Command sent, dlen=%d packet= ", dev->name, dlen); | ||
342 | for (k = 0; k < 12; k++) | ||
343 | printk("%02x ", cmd[k] & 0xff); | ||
344 | printk("\n"); | ||
345 | } | ||
346 | return 0; | ||
347 | fail: | ||
348 | pi_disconnect(dev->pi); | ||
349 | return -1; | ||
350 | } | ||
351 | |||
352 | static int pg_completion(struct pg *dev, char *buf, unsigned long tmo) | ||
353 | { | ||
354 | int r, d, n, p; | ||
355 | |||
356 | r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR, | ||
357 | tmo, "completion"); | ||
358 | |||
359 | dev->dlen = 0; | ||
360 | |||
361 | while (read_reg(dev, 7) & STAT_DRQ) { | ||
362 | d = (read_reg(dev, 4) + 256 * read_reg(dev, 5)); | ||
363 | n = ((d + 3) & 0xfffc); | ||
364 | p = read_reg(dev, 2) & 3; | ||
365 | if (p == 0) | ||
366 | pi_write_block(dev->pi, buf, n); | ||
367 | if (p == 2) | ||
368 | pi_read_block(dev->pi, buf, n); | ||
369 | if (verbose > 1) | ||
370 | printk("%s: %s %d bytes\n", dev->name, | ||
371 | p ? "Read" : "Write", n); | ||
372 | dev->dlen += (1 - p) * d; | ||
373 | buf += d; | ||
374 | r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR, | ||
375 | tmo, "completion"); | ||
376 | } | ||
377 | |||
378 | pi_disconnect(dev->pi); | ||
379 | |||
380 | return r; | ||
381 | } | ||
382 | |||
383 | static int pg_reset(struct pg *dev) | ||
384 | { | ||
385 | int i, k, err; | ||
386 | int expect[5] = { 1, 1, 1, 0x14, 0xeb }; | ||
387 | int got[5]; | ||
388 | |||
389 | pi_connect(dev->pi); | ||
390 | write_reg(dev, 6, DRIVE(dev)); | ||
391 | write_reg(dev, 7, 8); | ||
392 | |||
393 | pg_sleep(20 * HZ / 1000); | ||
394 | |||
395 | k = 0; | ||
396 | while ((k++ < PG_RESET_TMO) && (status_reg(dev) & STAT_BUSY)) | ||
397 | pg_sleep(1); | ||
398 | |||
399 | for (i = 0; i < 5; i++) | ||
400 | got[i] = read_reg(dev, i + 1); | ||
401 | |||
402 | err = memcmp(expect, got, sizeof(got)) ? -1 : 0; | ||
403 | |||
404 | if (verbose) { | ||
405 | printk("%s: Reset (%d) signature = ", dev->name, k); | ||
406 | for (i = 0; i < 5; i++) | ||
407 | printk("%3x", got[i]); | ||
408 | if (err) | ||
409 | printk(" (incorrect)"); | ||
410 | printk("\n"); | ||
411 | } | ||
412 | |||
413 | pi_disconnect(dev->pi); | ||
414 | return err; | ||
415 | } | ||
416 | |||
417 | static void xs(char *buf, char *targ, int len) | ||
418 | { | ||
419 | char l = '\0'; | ||
420 | int k; | ||
421 | |||
422 | for (k = 0; k < len; k++) { | ||
423 | char c = *buf++; | ||
424 | if (c != ' ' || c != l) | ||
425 | l = *targ++ = c; | ||
426 | } | ||
427 | if (l == ' ') | ||
428 | targ--; | ||
429 | *targ = '\0'; | ||
430 | } | ||
431 | |||
432 | static int pg_identify(struct pg *dev, int log) | ||
433 | { | ||
434 | int s; | ||
435 | char *ms[2] = { "master", "slave" }; | ||
436 | char mf[10], id[18]; | ||
437 | char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; | ||
438 | char buf[36]; | ||
439 | |||
440 | s = pg_command(dev, id_cmd, 36, jiffies + PG_TMO); | ||
441 | if (s) | ||
442 | return -1; | ||
443 | s = pg_completion(dev, buf, jiffies + PG_TMO); | ||
444 | if (s) | ||
445 | return -1; | ||
446 | |||
447 | if (log) { | ||
448 | xs(buf + 8, mf, 8); | ||
449 | xs(buf + 16, id, 16); | ||
450 | printk("%s: %s %s, %s\n", dev->name, mf, id, ms[dev->drive]); | ||
451 | } | ||
452 | |||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * returns 0, with id set if drive is detected | ||
458 | * -1, if drive detection failed | ||
459 | */ | ||
460 | static int pg_probe(struct pg *dev) | ||
461 | { | ||
462 | if (dev->drive == -1) { | ||
463 | for (dev->drive = 0; dev->drive <= 1; dev->drive++) | ||
464 | if (!pg_reset(dev)) | ||
465 | return pg_identify(dev, 1); | ||
466 | } else { | ||
467 | if (!pg_reset(dev)) | ||
468 | return pg_identify(dev, 1); | ||
469 | } | ||
470 | return -1; | ||
471 | } | ||
472 | |||
473 | static int pg_detect(void) | ||
474 | { | ||
475 | struct pg *dev = &devices[0]; | ||
476 | int k, unit; | ||
477 | |||
478 | printk("%s: %s version %s, major %d\n", name, name, PG_VERSION, major); | ||
479 | |||
480 | k = 0; | ||
481 | if (pg_drive_count == 0) { | ||
482 | if (pi_init(dev->pi, 1, -1, -1, -1, -1, -1, pg_scratch, | ||
483 | PI_PG, verbose, dev->name)) { | ||
484 | if (!pg_probe(dev)) { | ||
485 | dev->present = 1; | ||
486 | k++; | ||
487 | } else | ||
488 | pi_release(dev->pi); | ||
489 | } | ||
490 | |||
491 | } else | ||
492 | for (unit = 0; unit < PG_UNITS; unit++, dev++) { | ||
493 | int *parm = *drives[unit]; | ||
494 | if (!parm[D_PRT]) | ||
495 | continue; | ||
496 | if (pi_init(dev->pi, 0, parm[D_PRT], parm[D_MOD], | ||
497 | parm[D_UNI], parm[D_PRO], parm[D_DLY], | ||
498 | pg_scratch, PI_PG, verbose, dev->name)) { | ||
499 | if (!pg_probe(dev)) { | ||
500 | dev->present = 1; | ||
501 | k++; | ||
502 | } else | ||
503 | pi_release(dev->pi); | ||
504 | } | ||
505 | } | ||
506 | |||
507 | if (k) | ||
508 | return 0; | ||
509 | |||
510 | printk("%s: No ATAPI device detected\n", name); | ||
511 | return -1; | ||
512 | } | ||
513 | |||
514 | static int pg_open(struct inode *inode, struct file *file) | ||
515 | { | ||
516 | int unit = iminor(inode) & 0x7f; | ||
517 | struct pg *dev = &devices[unit]; | ||
518 | |||
519 | if ((unit >= PG_UNITS) || (!dev->present)) | ||
520 | return -ENODEV; | ||
521 | |||
522 | if (test_and_set_bit(0, &dev->access)) | ||
523 | return -EBUSY; | ||
524 | |||
525 | if (dev->busy) { | ||
526 | pg_reset(dev); | ||
527 | dev->busy = 0; | ||
528 | } | ||
529 | |||
530 | pg_identify(dev, (verbose > 1)); | ||
531 | |||
532 | dev->bufptr = kmalloc(PG_MAX_DATA, GFP_KERNEL); | ||
533 | if (dev->bufptr == NULL) { | ||
534 | clear_bit(0, &dev->access); | ||
535 | printk("%s: buffer allocation failed\n", dev->name); | ||
536 | return -ENOMEM; | ||
537 | } | ||
538 | |||
539 | file->private_data = dev; | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int pg_release(struct inode *inode, struct file *file) | ||
545 | { | ||
546 | struct pg *dev = file->private_data; | ||
547 | |||
548 | kfree(dev->bufptr); | ||
549 | dev->bufptr = NULL; | ||
550 | clear_bit(0, &dev->access); | ||
551 | |||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) | ||
556 | { | ||
557 | struct pg *dev = filp->private_data; | ||
558 | struct pg_write_hdr hdr; | ||
559 | int hs = sizeof (hdr); | ||
560 | |||
561 | if (dev->busy) | ||
562 | return -EBUSY; | ||
563 | if (count < hs) | ||
564 | return -EINVAL; | ||
565 | |||
566 | if (copy_from_user(&hdr, buf, hs)) | ||
567 | return -EFAULT; | ||
568 | |||
569 | if (hdr.magic != PG_MAGIC) | ||
570 | return -EINVAL; | ||
571 | if (hdr.dlen > PG_MAX_DATA) | ||
572 | return -EINVAL; | ||
573 | if ((count - hs) > PG_MAX_DATA) | ||
574 | return -EINVAL; | ||
575 | |||
576 | if (hdr.func == PG_RESET) { | ||
577 | if (count != hs) | ||
578 | return -EINVAL; | ||
579 | if (pg_reset(dev)) | ||
580 | return -EIO; | ||
581 | return count; | ||
582 | } | ||
583 | |||
584 | if (hdr.func != PG_COMMAND) | ||
585 | return -EINVAL; | ||
586 | |||
587 | dev->start = jiffies; | ||
588 | dev->timeout = hdr.timeout * HZ + HZ / 2 + jiffies; | ||
589 | |||
590 | if (pg_command(dev, hdr.packet, hdr.dlen, jiffies + PG_TMO)) { | ||
591 | if (dev->status & 0x10) | ||
592 | return -ETIME; | ||
593 | return -EIO; | ||
594 | } | ||
595 | |||
596 | dev->busy = 1; | ||
597 | |||
598 | if (copy_from_user(dev->bufptr, buf + hs, count - hs)) | ||
599 | return -EFAULT; | ||
600 | return count; | ||
601 | } | ||
602 | |||
603 | static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | ||
604 | { | ||
605 | struct pg *dev = filp->private_data; | ||
606 | struct pg_read_hdr hdr; | ||
607 | int hs = sizeof (hdr); | ||
608 | int copy; | ||
609 | |||
610 | if (!dev->busy) | ||
611 | return -EINVAL; | ||
612 | if (count < hs) | ||
613 | return -EINVAL; | ||
614 | |||
615 | dev->busy = 0; | ||
616 | |||
617 | if (pg_completion(dev, dev->bufptr, dev->timeout)) | ||
618 | if (dev->status & 0x10) | ||
619 | return -ETIME; | ||
620 | |||
621 | hdr.magic = PG_MAGIC; | ||
622 | hdr.dlen = dev->dlen; | ||
623 | copy = 0; | ||
624 | |||
625 | if (hdr.dlen < 0) { | ||
626 | hdr.dlen = -1 * hdr.dlen; | ||
627 | copy = hdr.dlen; | ||
628 | if (copy > (count - hs)) | ||
629 | copy = count - hs; | ||
630 | } | ||
631 | |||
632 | hdr.duration = (jiffies - dev->start + HZ / 2) / HZ; | ||
633 | hdr.scsi = dev->status & 0x0f; | ||
634 | |||
635 | if (copy_to_user(buf, &hdr, hs)) | ||
636 | return -EFAULT; | ||
637 | if (copy > 0) | ||
638 | if (copy_to_user(buf + hs, dev->bufptr, copy)) | ||
639 | return -EFAULT; | ||
640 | return copy + hs; | ||
641 | } | ||
642 | |||
643 | static int __init pg_init(void) | ||
644 | { | ||
645 | int unit, err = 0; | ||
646 | |||
647 | if (disable){ | ||
648 | err = -1; | ||
649 | goto out; | ||
650 | } | ||
651 | |||
652 | pg_init_units(); | ||
653 | |||
654 | if (pg_detect()) { | ||
655 | err = -1; | ||
656 | goto out; | ||
657 | } | ||
658 | |||
659 | if (register_chrdev(major, name, &pg_fops)) { | ||
660 | printk("pg_init: unable to get major number %d\n", major); | ||
661 | for (unit = 0; unit < PG_UNITS; unit++) { | ||
662 | struct pg *dev = &devices[unit]; | ||
663 | if (dev->present) | ||
664 | pi_release(dev->pi); | ||
665 | } | ||
666 | err = -1; | ||
667 | goto out; | ||
668 | } | ||
669 | pg_class = class_simple_create(THIS_MODULE, "pg"); | ||
670 | if (IS_ERR(pg_class)) { | ||
671 | err = PTR_ERR(pg_class); | ||
672 | goto out_chrdev; | ||
673 | } | ||
674 | devfs_mk_dir("pg"); | ||
675 | for (unit = 0; unit < PG_UNITS; unit++) { | ||
676 | struct pg *dev = &devices[unit]; | ||
677 | if (dev->present) { | ||
678 | class_simple_device_add(pg_class, MKDEV(major, unit), | ||
679 | NULL, "pg%u", unit); | ||
680 | err = devfs_mk_cdev(MKDEV(major, unit), | ||
681 | S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u", | ||
682 | unit); | ||
683 | if (err) | ||
684 | goto out_class; | ||
685 | } | ||
686 | } | ||
687 | err = 0; | ||
688 | goto out; | ||
689 | |||
690 | out_class: | ||
691 | class_simple_device_remove(MKDEV(major, unit)); | ||
692 | class_simple_destroy(pg_class); | ||
693 | out_chrdev: | ||
694 | unregister_chrdev(major, "pg"); | ||
695 | out: | ||
696 | return err; | ||
697 | } | ||
698 | |||
699 | static void __exit pg_exit(void) | ||
700 | { | ||
701 | int unit; | ||
702 | |||
703 | for (unit = 0; unit < PG_UNITS; unit++) { | ||
704 | struct pg *dev = &devices[unit]; | ||
705 | if (dev->present) { | ||
706 | class_simple_device_remove(MKDEV(major, unit)); | ||
707 | devfs_remove("pg/%u", unit); | ||
708 | } | ||
709 | } | ||
710 | class_simple_destroy(pg_class); | ||
711 | devfs_remove("pg"); | ||
712 | unregister_chrdev(major, name); | ||
713 | |||
714 | for (unit = 0; unit < PG_UNITS; unit++) { | ||
715 | struct pg *dev = &devices[unit]; | ||
716 | if (dev->present) | ||
717 | pi_release(dev->pi); | ||
718 | } | ||
719 | } | ||
720 | |||
721 | MODULE_LICENSE("GPL"); | ||
722 | module_init(pg_init) | ||
723 | module_exit(pg_exit) | ||
diff --git a/drivers/block/paride/ppc6lnx.c b/drivers/block/paride/ppc6lnx.c new file mode 100644 index 000000000000..5e5521d3b1dd --- /dev/null +++ b/drivers/block/paride/ppc6lnx.c | |||
@@ -0,0 +1,726 @@ | |||
1 | /* | ||
2 | ppc6lnx.c (c) 2001 Micro Solutions Inc. | ||
3 | Released under the terms of the GNU General Public license | ||
4 | |||
5 | ppc6lnx.c is a par of the protocol driver for the Micro Solutions | ||
6 | "BACKPACK" parallel port IDE adapter | ||
7 | (Works on Series 6 drives) | ||
8 | |||
9 | */ | ||
10 | |||
11 | //*************************************************************************** | ||
12 | |||
13 | // PPC 6 Code in C sanitized for LINUX | ||
14 | // Original x86 ASM by Ron, Converted to C by Clive | ||
15 | |||
16 | //*************************************************************************** | ||
17 | |||
18 | |||
19 | #define port_stb 1 | ||
20 | #define port_afd 2 | ||
21 | #define cmd_stb port_afd | ||
22 | #define port_init 4 | ||
23 | #define data_stb port_init | ||
24 | #define port_sel 8 | ||
25 | #define port_int 16 | ||
26 | #define port_dir 0x20 | ||
27 | |||
28 | #define ECR_EPP 0x80 | ||
29 | #define ECR_BI 0x20 | ||
30 | |||
31 | //*************************************************************************** | ||
32 | |||
33 | // 60772 Commands | ||
34 | |||
35 | #define ACCESS_REG 0x00 | ||
36 | #define ACCESS_PORT 0x40 | ||
37 | |||
38 | #define ACCESS_READ 0x00 | ||
39 | #define ACCESS_WRITE 0x20 | ||
40 | |||
41 | // 60772 Command Prefix | ||
42 | |||
43 | #define CMD_PREFIX_SET 0xe0 // Special command that modifies the next command's operation | ||
44 | #define CMD_PREFIX_RESET 0xc0 // Resets current cmd modifier reg bits | ||
45 | #define PREFIX_IO16 0x01 // perform 16-bit wide I/O | ||
46 | #define PREFIX_FASTWR 0x04 // enable PPC mode fast-write | ||
47 | #define PREFIX_BLK 0x08 // enable block transfer mode | ||
48 | |||
49 | // 60772 Registers | ||
50 | |||
51 | #define REG_STATUS 0x00 // status register | ||
52 | #define STATUS_IRQA 0x01 // Peripheral IRQA line | ||
53 | #define STATUS_EEPROM_DO 0x40 // Serial EEPROM data bit | ||
54 | #define REG_VERSION 0x01 // PPC version register (read) | ||
55 | #define REG_HWCFG 0x02 // Hardware Config register | ||
56 | #define REG_RAMSIZE 0x03 // Size of RAM Buffer | ||
57 | #define RAMSIZE_128K 0x02 | ||
58 | #define REG_EEPROM 0x06 // EEPROM control register | ||
59 | #define EEPROM_SK 0x01 // eeprom SK bit | ||
60 | #define EEPROM_DI 0x02 // eeprom DI bit | ||
61 | #define EEPROM_CS 0x04 // eeprom CS bit | ||
62 | #define EEPROM_EN 0x08 // eeprom output enable | ||
63 | #define REG_BLKSIZE 0x08 // Block transfer len (24 bit) | ||
64 | |||
65 | //*************************************************************************** | ||
66 | |||
67 | typedef struct ppc_storage { | ||
68 | u16 lpt_addr; // LPT base address | ||
69 | u8 ppc_id; | ||
70 | u8 mode; // operating mode | ||
71 | // 0 = PPC Uni SW | ||
72 | // 1 = PPC Uni FW | ||
73 | // 2 = PPC Bi SW | ||
74 | // 3 = PPC Bi FW | ||
75 | // 4 = EPP Byte | ||
76 | // 5 = EPP Word | ||
77 | // 6 = EPP Dword | ||
78 | u8 ppc_flags; | ||
79 | u8 org_data; // original LPT data port contents | ||
80 | u8 org_ctrl; // original LPT control port contents | ||
81 | u8 cur_ctrl; // current control port contents | ||
82 | } Interface; | ||
83 | |||
84 | //*************************************************************************** | ||
85 | |||
86 | // ppc_flags | ||
87 | |||
88 | #define fifo_wait 0x10 | ||
89 | |||
90 | //*************************************************************************** | ||
91 | |||
92 | // DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES | ||
93 | |||
94 | #define PPCMODE_UNI_SW 0 | ||
95 | #define PPCMODE_UNI_FW 1 | ||
96 | #define PPCMODE_BI_SW 2 | ||
97 | #define PPCMODE_BI_FW 3 | ||
98 | #define PPCMODE_EPP_BYTE 4 | ||
99 | #define PPCMODE_EPP_WORD 5 | ||
100 | #define PPCMODE_EPP_DWORD 6 | ||
101 | |||
102 | //*************************************************************************** | ||
103 | |||
104 | static int ppc6_select(Interface *ppc); | ||
105 | static void ppc6_deselect(Interface *ppc); | ||
106 | static void ppc6_send_cmd(Interface *ppc, u8 cmd); | ||
107 | static void ppc6_wr_data_byte(Interface *ppc, u8 data); | ||
108 | static u8 ppc6_rd_data_byte(Interface *ppc); | ||
109 | static u8 ppc6_rd_port(Interface *ppc, u8 port); | ||
110 | static void ppc6_wr_port(Interface *ppc, u8 port, u8 data); | ||
111 | static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count); | ||
112 | static void ppc6_wait_for_fifo(Interface *ppc); | ||
113 | static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count); | ||
114 | static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length); | ||
115 | static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length); | ||
116 | static void ppc6_wr_extout(Interface *ppc, u8 regdata); | ||
117 | static int ppc6_open(Interface *ppc); | ||
118 | static void ppc6_close(Interface *ppc); | ||
119 | |||
120 | //*************************************************************************** | ||
121 | |||
122 | static int ppc6_select(Interface *ppc) | ||
123 | { | ||
124 | u8 i, j, k; | ||
125 | |||
126 | i = inb(ppc->lpt_addr + 1); | ||
127 | |||
128 | if (i & 1) | ||
129 | outb(i, ppc->lpt_addr + 1); | ||
130 | |||
131 | ppc->org_data = inb(ppc->lpt_addr); | ||
132 | |||
133 | ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl | ||
134 | |||
135 | ppc->cur_ctrl = ppc->org_ctrl; | ||
136 | |||
137 | ppc->cur_ctrl |= port_sel; | ||
138 | |||
139 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
140 | |||
141 | if (ppc->org_data == 'b') | ||
142 | outb('x', ppc->lpt_addr); | ||
143 | |||
144 | outb('b', ppc->lpt_addr); | ||
145 | outb('p', ppc->lpt_addr); | ||
146 | outb(ppc->ppc_id, ppc->lpt_addr); | ||
147 | outb(~ppc->ppc_id,ppc->lpt_addr); | ||
148 | |||
149 | ppc->cur_ctrl &= ~port_sel; | ||
150 | |||
151 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
152 | |||
153 | ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init; | ||
154 | |||
155 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
156 | |||
157 | i = ppc->mode & 0x0C; | ||
158 | |||
159 | if (i == 0) | ||
160 | i = (ppc->mode & 2) | 1; | ||
161 | |||
162 | outb(i, ppc->lpt_addr); | ||
163 | |||
164 | ppc->cur_ctrl |= port_sel; | ||
165 | |||
166 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
167 | |||
168 | // DELAY | ||
169 | |||
170 | ppc->cur_ctrl |= port_afd; | ||
171 | |||
172 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
173 | |||
174 | j = ((i & 0x08) << 4) | ((i & 0x07) << 3); | ||
175 | |||
176 | k = inb(ppc->lpt_addr + 1) & 0xB8; | ||
177 | |||
178 | if (j == k) | ||
179 | { | ||
180 | ppc->cur_ctrl &= ~port_afd; | ||
181 | |||
182 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
183 | |||
184 | k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8; | ||
185 | |||
186 | if (j == k) | ||
187 | { | ||
188 | if (i & 4) // EPP | ||
189 | ppc->cur_ctrl &= ~(port_sel | port_init); | ||
190 | else // PPC/ECP | ||
191 | ppc->cur_ctrl &= ~port_sel; | ||
192 | |||
193 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
194 | |||
195 | return(1); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | outb(ppc->org_ctrl, ppc->lpt_addr + 2); | ||
200 | |||
201 | outb(ppc->org_data, ppc->lpt_addr); | ||
202 | |||
203 | return(0); // FAIL | ||
204 | } | ||
205 | |||
206 | //*************************************************************************** | ||
207 | |||
208 | static void ppc6_deselect(Interface *ppc) | ||
209 | { | ||
210 | if (ppc->mode & 4) // EPP | ||
211 | ppc->cur_ctrl |= port_init; | ||
212 | else // PPC/ECP | ||
213 | ppc->cur_ctrl |= port_sel; | ||
214 | |||
215 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
216 | |||
217 | outb(ppc->org_data, ppc->lpt_addr); | ||
218 | |||
219 | outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2); | ||
220 | |||
221 | outb(ppc->org_ctrl, ppc->lpt_addr + 2); | ||
222 | } | ||
223 | |||
224 | //*************************************************************************** | ||
225 | |||
226 | static void ppc6_send_cmd(Interface *ppc, u8 cmd) | ||
227 | { | ||
228 | switch(ppc->mode) | ||
229 | { | ||
230 | case PPCMODE_UNI_SW : | ||
231 | case PPCMODE_UNI_FW : | ||
232 | case PPCMODE_BI_SW : | ||
233 | case PPCMODE_BI_FW : | ||
234 | { | ||
235 | outb(cmd, ppc->lpt_addr); | ||
236 | |||
237 | ppc->cur_ctrl ^= cmd_stb; | ||
238 | |||
239 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
240 | |||
241 | break; | ||
242 | } | ||
243 | |||
244 | case PPCMODE_EPP_BYTE : | ||
245 | case PPCMODE_EPP_WORD : | ||
246 | case PPCMODE_EPP_DWORD : | ||
247 | { | ||
248 | outb(cmd, ppc->lpt_addr + 3); | ||
249 | |||
250 | break; | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | |||
255 | //*************************************************************************** | ||
256 | |||
257 | static void ppc6_wr_data_byte(Interface *ppc, u8 data) | ||
258 | { | ||
259 | switch(ppc->mode) | ||
260 | { | ||
261 | case PPCMODE_UNI_SW : | ||
262 | case PPCMODE_UNI_FW : | ||
263 | case PPCMODE_BI_SW : | ||
264 | case PPCMODE_BI_FW : | ||
265 | { | ||
266 | outb(data, ppc->lpt_addr); | ||
267 | |||
268 | ppc->cur_ctrl ^= data_stb; | ||
269 | |||
270 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
271 | |||
272 | break; | ||
273 | } | ||
274 | |||
275 | case PPCMODE_EPP_BYTE : | ||
276 | case PPCMODE_EPP_WORD : | ||
277 | case PPCMODE_EPP_DWORD : | ||
278 | { | ||
279 | outb(data, ppc->lpt_addr + 4); | ||
280 | |||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | |||
286 | //*************************************************************************** | ||
287 | |||
288 | static u8 ppc6_rd_data_byte(Interface *ppc) | ||
289 | { | ||
290 | u8 data = 0; | ||
291 | |||
292 | switch(ppc->mode) | ||
293 | { | ||
294 | case PPCMODE_UNI_SW : | ||
295 | case PPCMODE_UNI_FW : | ||
296 | { | ||
297 | ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb; | ||
298 | |||
299 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
300 | |||
301 | // DELAY | ||
302 | |||
303 | data = inb(ppc->lpt_addr + 1); | ||
304 | |||
305 | data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3); | ||
306 | |||
307 | ppc->cur_ctrl |= port_stb; | ||
308 | |||
309 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
310 | |||
311 | // DELAY | ||
312 | |||
313 | data |= inb(ppc->lpt_addr + 1) & 0xB8; | ||
314 | |||
315 | break; | ||
316 | } | ||
317 | |||
318 | case PPCMODE_BI_SW : | ||
319 | case PPCMODE_BI_FW : | ||
320 | { | ||
321 | ppc->cur_ctrl |= port_dir; | ||
322 | |||
323 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
324 | |||
325 | ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb; | ||
326 | |||
327 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
328 | |||
329 | data = inb(ppc->lpt_addr); | ||
330 | |||
331 | ppc->cur_ctrl &= ~port_stb; | ||
332 | |||
333 | outb(ppc->cur_ctrl,ppc->lpt_addr + 2); | ||
334 | |||
335 | ppc->cur_ctrl &= ~port_dir; | ||
336 | |||
337 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
338 | |||
339 | break; | ||
340 | } | ||
341 | |||
342 | case PPCMODE_EPP_BYTE : | ||
343 | case PPCMODE_EPP_WORD : | ||
344 | case PPCMODE_EPP_DWORD : | ||
345 | { | ||
346 | outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2); | ||
347 | |||
348 | data = inb(ppc->lpt_addr + 4); | ||
349 | |||
350 | outb(ppc->cur_ctrl,ppc->lpt_addr + 2); | ||
351 | |||
352 | break; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | return(data); | ||
357 | } | ||
358 | |||
359 | //*************************************************************************** | ||
360 | |||
361 | static u8 ppc6_rd_port(Interface *ppc, u8 port) | ||
362 | { | ||
363 | ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ)); | ||
364 | |||
365 | return(ppc6_rd_data_byte(ppc)); | ||
366 | } | ||
367 | |||
368 | //*************************************************************************** | ||
369 | |||
370 | static void ppc6_wr_port(Interface *ppc, u8 port, u8 data) | ||
371 | { | ||
372 | ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE)); | ||
373 | |||
374 | ppc6_wr_data_byte(ppc, data); | ||
375 | } | ||
376 | |||
377 | //*************************************************************************** | ||
378 | |||
379 | static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count) | ||
380 | { | ||
381 | switch(ppc->mode) | ||
382 | { | ||
383 | case PPCMODE_UNI_SW : | ||
384 | case PPCMODE_UNI_FW : | ||
385 | { | ||
386 | while(count) | ||
387 | { | ||
388 | u8 d; | ||
389 | |||
390 | ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb; | ||
391 | |||
392 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
393 | |||
394 | // DELAY | ||
395 | |||
396 | d = inb(ppc->lpt_addr + 1); | ||
397 | |||
398 | d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3); | ||
399 | |||
400 | ppc->cur_ctrl |= port_stb; | ||
401 | |||
402 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
403 | |||
404 | // DELAY | ||
405 | |||
406 | d |= inb(ppc->lpt_addr + 1) & 0xB8; | ||
407 | |||
408 | *data++ = d; | ||
409 | count--; | ||
410 | } | ||
411 | |||
412 | break; | ||
413 | } | ||
414 | |||
415 | case PPCMODE_BI_SW : | ||
416 | case PPCMODE_BI_FW : | ||
417 | { | ||
418 | ppc->cur_ctrl |= port_dir; | ||
419 | |||
420 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
421 | |||
422 | ppc->cur_ctrl |= port_stb; | ||
423 | |||
424 | while(count) | ||
425 | { | ||
426 | ppc->cur_ctrl ^= data_stb; | ||
427 | |||
428 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
429 | |||
430 | *data++ = inb(ppc->lpt_addr); | ||
431 | count--; | ||
432 | } | ||
433 | |||
434 | ppc->cur_ctrl &= ~port_stb; | ||
435 | |||
436 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
437 | |||
438 | ppc->cur_ctrl &= ~port_dir; | ||
439 | |||
440 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
441 | |||
442 | break; | ||
443 | } | ||
444 | |||
445 | case PPCMODE_EPP_BYTE : | ||
446 | { | ||
447 | outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2); | ||
448 | |||
449 | // DELAY | ||
450 | |||
451 | while(count) | ||
452 | { | ||
453 | *data++ = inb(ppc->lpt_addr + 4); | ||
454 | count--; | ||
455 | } | ||
456 | |||
457 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
458 | |||
459 | break; | ||
460 | } | ||
461 | |||
462 | case PPCMODE_EPP_WORD : | ||
463 | { | ||
464 | outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2); | ||
465 | |||
466 | // DELAY | ||
467 | |||
468 | while(count > 1) | ||
469 | { | ||
470 | *((u16 *)data) = inw(ppc->lpt_addr + 4); | ||
471 | data += 2; | ||
472 | count -= 2; | ||
473 | } | ||
474 | |||
475 | while(count) | ||
476 | { | ||
477 | *data++ = inb(ppc->lpt_addr + 4); | ||
478 | count--; | ||
479 | } | ||
480 | |||
481 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
482 | |||
483 | break; | ||
484 | } | ||
485 | |||
486 | case PPCMODE_EPP_DWORD : | ||
487 | { | ||
488 | outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2); | ||
489 | |||
490 | // DELAY | ||
491 | |||
492 | while(count > 3) | ||
493 | { | ||
494 | *((u32 *)data) = inl(ppc->lpt_addr + 4); | ||
495 | data += 4; | ||
496 | count -= 4; | ||
497 | } | ||
498 | |||
499 | while(count) | ||
500 | { | ||
501 | *data++ = inb(ppc->lpt_addr + 4); | ||
502 | count--; | ||
503 | } | ||
504 | |||
505 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
506 | |||
507 | break; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | } | ||
512 | |||
513 | //*************************************************************************** | ||
514 | |||
515 | static void ppc6_wait_for_fifo(Interface *ppc) | ||
516 | { | ||
517 | int i; | ||
518 | |||
519 | if (ppc->ppc_flags & fifo_wait) | ||
520 | { | ||
521 | for(i=0; i<20; i++) | ||
522 | inb(ppc->lpt_addr + 1); | ||
523 | } | ||
524 | } | ||
525 | |||
526 | //*************************************************************************** | ||
527 | |||
528 | static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count) | ||
529 | { | ||
530 | switch(ppc->mode) | ||
531 | { | ||
532 | case PPCMODE_UNI_SW : | ||
533 | case PPCMODE_BI_SW : | ||
534 | { | ||
535 | while(count--) | ||
536 | { | ||
537 | outb(*data++, ppc->lpt_addr); | ||
538 | |||
539 | ppc->cur_ctrl ^= data_stb; | ||
540 | |||
541 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
542 | } | ||
543 | |||
544 | break; | ||
545 | } | ||
546 | |||
547 | case PPCMODE_UNI_FW : | ||
548 | case PPCMODE_BI_FW : | ||
549 | { | ||
550 | u8 this, last; | ||
551 | |||
552 | ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR)); | ||
553 | |||
554 | ppc->cur_ctrl |= port_stb; | ||
555 | |||
556 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
557 | |||
558 | last = *data; | ||
559 | |||
560 | outb(last, ppc->lpt_addr); | ||
561 | |||
562 | while(count) | ||
563 | { | ||
564 | this = *data++; | ||
565 | count--; | ||
566 | |||
567 | if (this == last) | ||
568 | { | ||
569 | ppc->cur_ctrl ^= data_stb; | ||
570 | |||
571 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | outb(this, ppc->lpt_addr); | ||
576 | |||
577 | last = this; | ||
578 | } | ||
579 | } | ||
580 | |||
581 | ppc->cur_ctrl &= ~port_stb; | ||
582 | |||
583 | outb(ppc->cur_ctrl, ppc->lpt_addr + 2); | ||
584 | |||
585 | ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR)); | ||
586 | |||
587 | break; | ||
588 | } | ||
589 | |||
590 | case PPCMODE_EPP_BYTE : | ||
591 | { | ||
592 | while(count) | ||
593 | { | ||
594 | outb(*data++,ppc->lpt_addr + 4); | ||
595 | count--; | ||
596 | } | ||
597 | |||
598 | ppc6_wait_for_fifo(ppc); | ||
599 | |||
600 | break; | ||
601 | } | ||
602 | |||
603 | case PPCMODE_EPP_WORD : | ||
604 | { | ||
605 | while(count > 1) | ||
606 | { | ||
607 | outw(*((u16 *)data),ppc->lpt_addr + 4); | ||
608 | data += 2; | ||
609 | count -= 2; | ||
610 | } | ||
611 | |||
612 | while(count) | ||
613 | { | ||
614 | outb(*data++,ppc->lpt_addr + 4); | ||
615 | count--; | ||
616 | } | ||
617 | |||
618 | ppc6_wait_for_fifo(ppc); | ||
619 | |||
620 | break; | ||
621 | } | ||
622 | |||
623 | case PPCMODE_EPP_DWORD : | ||
624 | { | ||
625 | while(count > 3) | ||
626 | { | ||
627 | outl(*((u32 *)data),ppc->lpt_addr + 4); | ||
628 | data += 4; | ||
629 | count -= 4; | ||
630 | } | ||
631 | |||
632 | while(count) | ||
633 | { | ||
634 | outb(*data++,ppc->lpt_addr + 4); | ||
635 | count--; | ||
636 | } | ||
637 | |||
638 | ppc6_wait_for_fifo(ppc); | ||
639 | |||
640 | break; | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | |||
645 | //*************************************************************************** | ||
646 | |||
647 | static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length) | ||
648 | { | ||
649 | length = length << 1; | ||
650 | |||
651 | ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE)); | ||
652 | ppc6_wr_data_byte(ppc,(u8)length); | ||
653 | ppc6_wr_data_byte(ppc,(u8)(length >> 8)); | ||
654 | ppc6_wr_data_byte(ppc,0); | ||
655 | |||
656 | ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK)); | ||
657 | |||
658 | ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ)); | ||
659 | |||
660 | ppc6_rd_data_blk(ppc, data, length); | ||
661 | |||
662 | ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK)); | ||
663 | } | ||
664 | |||
665 | //*************************************************************************** | ||
666 | |||
667 | static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length) | ||
668 | { | ||
669 | length = length << 1; | ||
670 | |||
671 | ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE)); | ||
672 | ppc6_wr_data_byte(ppc,(u8)length); | ||
673 | ppc6_wr_data_byte(ppc,(u8)(length >> 8)); | ||
674 | ppc6_wr_data_byte(ppc,0); | ||
675 | |||
676 | ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK)); | ||
677 | |||
678 | ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE)); | ||
679 | |||
680 | ppc6_wr_data_blk(ppc, data, length); | ||
681 | |||
682 | ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK)); | ||
683 | } | ||
684 | |||
685 | //*************************************************************************** | ||
686 | |||
687 | static void ppc6_wr_extout(Interface *ppc, u8 regdata) | ||
688 | { | ||
689 | ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE)); | ||
690 | |||
691 | ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6)); | ||
692 | } | ||
693 | |||
694 | //*************************************************************************** | ||
695 | |||
696 | static int ppc6_open(Interface *ppc) | ||
697 | { | ||
698 | int ret; | ||
699 | |||
700 | ret = ppc6_select(ppc); | ||
701 | |||
702 | if (ret == 0) | ||
703 | return(ret); | ||
704 | |||
705 | ppc->ppc_flags &= ~fifo_wait; | ||
706 | |||
707 | ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE)); | ||
708 | ppc6_wr_data_byte(ppc, RAMSIZE_128K); | ||
709 | |||
710 | ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION)); | ||
711 | |||
712 | if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C) | ||
713 | ppc->ppc_flags |= fifo_wait; | ||
714 | |||
715 | return(ret); | ||
716 | } | ||
717 | |||
718 | //*************************************************************************** | ||
719 | |||
720 | static void ppc6_close(Interface *ppc) | ||
721 | { | ||
722 | ppc6_deselect(ppc); | ||
723 | } | ||
724 | |||
725 | //*************************************************************************** | ||
726 | |||
diff --git a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h new file mode 100644 index 000000000000..932342d7a8eb --- /dev/null +++ b/drivers/block/paride/pseudo.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | pseudo.h (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is the "pseudo-interrupt" logic for parallel port drivers. | ||
6 | |||
7 | This module is #included into each driver. It makes one | ||
8 | function available: | ||
9 | |||
10 | ps_set_intr( void (*continuation)(void), | ||
11 | int (*ready)(void), | ||
12 | int timeout, | ||
13 | int nice ) | ||
14 | |||
15 | Which will arrange for ready() to be evaluated frequently and | ||
16 | when either it returns true, or timeout jiffies have passed, | ||
17 | continuation() will be invoked. | ||
18 | |||
19 | If nice is 1, the test will done approximately once a | ||
20 | jiffy. If nice is 0, the test will also be done whenever | ||
21 | the scheduler runs (by adding it to a task queue). If | ||
22 | nice is greater than 1, the test will be done once every | ||
23 | (nice-1) jiffies. | ||
24 | |||
25 | */ | ||
26 | |||
27 | /* Changes: | ||
28 | |||
29 | 1.01 1998.05.03 Switched from cli()/sti() to spinlocks | ||
30 | 1.02 1998.12.14 Added support for nice > 1 | ||
31 | */ | ||
32 | |||
33 | #define PS_VERSION "1.02" | ||
34 | |||
35 | #include <linux/sched.h> | ||
36 | #include <linux/workqueue.h> | ||
37 | |||
38 | static void ps_tq_int( void *data); | ||
39 | |||
40 | static void (* ps_continuation)(void); | ||
41 | static int (* ps_ready)(void); | ||
42 | static unsigned long ps_timeout; | ||
43 | static int ps_tq_active = 0; | ||
44 | static int ps_nice = 0; | ||
45 | |||
46 | static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused))); | ||
47 | |||
48 | static DECLARE_WORK(ps_tq, ps_tq_int, NULL); | ||
49 | |||
50 | static void ps_set_intr(void (*continuation)(void), | ||
51 | int (*ready)(void), | ||
52 | int timeout, int nice) | ||
53 | { | ||
54 | unsigned long flags; | ||
55 | |||
56 | spin_lock_irqsave(&ps_spinlock,flags); | ||
57 | |||
58 | ps_continuation = continuation; | ||
59 | ps_ready = ready; | ||
60 | ps_timeout = jiffies + timeout; | ||
61 | ps_nice = nice; | ||
62 | |||
63 | if (!ps_tq_active) { | ||
64 | ps_tq_active = 1; | ||
65 | if (!ps_nice) | ||
66 | schedule_work(&ps_tq); | ||
67 | else | ||
68 | schedule_delayed_work(&ps_tq, ps_nice-1); | ||
69 | } | ||
70 | spin_unlock_irqrestore(&ps_spinlock,flags); | ||
71 | } | ||
72 | |||
73 | static void ps_tq_int(void *data) | ||
74 | { | ||
75 | void (*con)(void); | ||
76 | unsigned long flags; | ||
77 | |||
78 | spin_lock_irqsave(&ps_spinlock,flags); | ||
79 | |||
80 | con = ps_continuation; | ||
81 | ps_tq_active = 0; | ||
82 | |||
83 | if (!con) { | ||
84 | spin_unlock_irqrestore(&ps_spinlock,flags); | ||
85 | return; | ||
86 | } | ||
87 | if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) { | ||
88 | ps_continuation = NULL; | ||
89 | spin_unlock_irqrestore(&ps_spinlock,flags); | ||
90 | con(); | ||
91 | return; | ||
92 | } | ||
93 | ps_tq_active = 1; | ||
94 | if (!ps_nice) | ||
95 | schedule_work(&ps_tq); | ||
96 | else | ||
97 | schedule_delayed_work(&ps_tq, ps_nice-1); | ||
98 | spin_unlock_irqrestore(&ps_spinlock,flags); | ||
99 | } | ||
100 | |||
101 | /* end of pseudo.h */ | ||
102 | |||
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c new file mode 100644 index 000000000000..8fbd6922fe0d --- /dev/null +++ b/drivers/block/paride/pt.c | |||
@@ -0,0 +1,1024 @@ | |||
1 | /* | ||
2 | pt.c (c) 1998 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is the high-level driver for parallel port ATAPI tape | ||
6 | drives based on chips supported by the paride module. | ||
7 | |||
8 | The driver implements both rewinding and non-rewinding | ||
9 | devices, filemarks, and the rewind ioctl. It allocates | ||
10 | a small internal "bounce buffer" for each open device, but | ||
11 | otherwise expects buffering and blocking to be done at the | ||
12 | user level. As with most block-structured tapes, short | ||
13 | writes are padded to full tape blocks, so reading back a file | ||
14 | may return more data than was actually written. | ||
15 | |||
16 | By default, the driver will autoprobe for a single parallel | ||
17 | port ATAPI tape drive, but if their individual parameters are | ||
18 | specified, the driver can handle up to 4 drives. | ||
19 | |||
20 | The rewinding devices are named /dev/pt0, /dev/pt1, ... | ||
21 | while the non-rewinding devices are /dev/npt0, /dev/npt1, etc. | ||
22 | |||
23 | The behaviour of the pt driver can be altered by setting | ||
24 | some parameters from the insmod command line. The following | ||
25 | parameters are adjustable: | ||
26 | |||
27 | drive0 These four arguments can be arrays of | ||
28 | drive1 1-6 integers as follows: | ||
29 | drive2 | ||
30 | drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly> | ||
31 | |||
32 | Where, | ||
33 | |||
34 | <prt> is the base of the parallel port address for | ||
35 | the corresponding drive. (required) | ||
36 | |||
37 | <pro> is the protocol number for the adapter that | ||
38 | supports this drive. These numbers are | ||
39 | logged by 'paride' when the protocol modules | ||
40 | are initialised. (0 if not given) | ||
41 | |||
42 | <uni> for those adapters that support chained | ||
43 | devices, this is the unit selector for the | ||
44 | chain of devices on the given port. It should | ||
45 | be zero for devices that don't support chaining. | ||
46 | (0 if not given) | ||
47 | |||
48 | <mod> this can be -1 to choose the best mode, or one | ||
49 | of the mode numbers supported by the adapter. | ||
50 | (-1 if not given) | ||
51 | |||
52 | <slv> ATAPI devices can be jumpered to master or slave. | ||
53 | Set this to 0 to choose the master drive, 1 to | ||
54 | choose the slave, -1 (the default) to choose the | ||
55 | first drive found. | ||
56 | |||
57 | <dly> some parallel ports require the driver to | ||
58 | go more slowly. -1 sets a default value that | ||
59 | should work with the chosen protocol. Otherwise, | ||
60 | set this to a small integer, the larger it is | ||
61 | the slower the port i/o. In some cases, setting | ||
62 | this to zero will speed up the device. (default -1) | ||
63 | |||
64 | major You may use this parameter to overide the | ||
65 | default major number (96) that this driver | ||
66 | will use. Be sure to change the device | ||
67 | name as well. | ||
68 | |||
69 | name This parameter is a character string that | ||
70 | contains the name the kernel will use for this | ||
71 | device (in /proc output, for instance). | ||
72 | (default "pt"). | ||
73 | |||
74 | verbose This parameter controls the amount of logging | ||
75 | that the driver will do. Set it to 0 for | ||
76 | normal operation, 1 to see autoprobe progress | ||
77 | messages, or 2 to see additional debugging | ||
78 | output. (default 0) | ||
79 | |||
80 | If this driver is built into the kernel, you can use | ||
81 | the following command line parameters, with the same values | ||
82 | as the corresponding module parameters listed above: | ||
83 | |||
84 | pt.drive0 | ||
85 | pt.drive1 | ||
86 | pt.drive2 | ||
87 | pt.drive3 | ||
88 | |||
89 | In addition, you can use the parameter pt.disable to disable | ||
90 | the driver entirely. | ||
91 | |||
92 | */ | ||
93 | |||
94 | /* Changes: | ||
95 | |||
96 | 1.01 GRG 1998.05.06 Round up transfer size, fix ready_wait, | ||
97 | loosed interpretation of ATAPI standard | ||
98 | for clearing error status. | ||
99 | Eliminate sti(); | ||
100 | 1.02 GRG 1998.06.16 Eliminate an Ugh. | ||
101 | 1.03 GRG 1998.08.15 Adjusted PT_TMO, use HZ in loop timing, | ||
102 | extra debugging | ||
103 | 1.04 GRG 1998.09.24 Repair minor coding error, added jumbo support | ||
104 | |||
105 | */ | ||
106 | |||
107 | #define PT_VERSION "1.04" | ||
108 | #define PT_MAJOR 96 | ||
109 | #define PT_NAME "pt" | ||
110 | #define PT_UNITS 4 | ||
111 | |||
112 | /* Here are things one can override from the insmod command. | ||
113 | Most are autoprobed by paride unless set here. Verbose is on | ||
114 | by default. | ||
115 | |||
116 | */ | ||
117 | |||
118 | static int verbose = 0; | ||
119 | static int major = PT_MAJOR; | ||
120 | static char *name = PT_NAME; | ||
121 | static int disable = 0; | ||
122 | |||
123 | static int drive0[6] = { 0, 0, 0, -1, -1, -1 }; | ||
124 | static int drive1[6] = { 0, 0, 0, -1, -1, -1 }; | ||
125 | static int drive2[6] = { 0, 0, 0, -1, -1, -1 }; | ||
126 | static int drive3[6] = { 0, 0, 0, -1, -1, -1 }; | ||
127 | |||
128 | static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; | ||
129 | |||
130 | #define D_PRT 0 | ||
131 | #define D_PRO 1 | ||
132 | #define D_UNI 2 | ||
133 | #define D_MOD 3 | ||
134 | #define D_SLV 4 | ||
135 | #define D_DLY 5 | ||
136 | |||
137 | #define DU (*drives[unit]) | ||
138 | |||
139 | /* end of parameters */ | ||
140 | |||
141 | #include <linux/module.h> | ||
142 | #include <linux/init.h> | ||
143 | #include <linux/fs.h> | ||
144 | #include <linux/devfs_fs_kernel.h> | ||
145 | #include <linux/delay.h> | ||
146 | #include <linux/slab.h> | ||
147 | #include <linux/mtio.h> | ||
148 | #include <linux/device.h> | ||
149 | |||
150 | #include <asm/uaccess.h> | ||
151 | |||
152 | module_param(verbose, bool, 0); | ||
153 | module_param(major, int, 0); | ||
154 | module_param(name, charp, 0); | ||
155 | module_param_array(drive0, int, NULL, 0); | ||
156 | module_param_array(drive1, int, NULL, 0); | ||
157 | module_param_array(drive2, int, NULL, 0); | ||
158 | module_param_array(drive3, int, NULL, 0); | ||
159 | |||
160 | #include "paride.h" | ||
161 | |||
162 | #define PT_MAX_RETRIES 5 | ||
163 | #define PT_TMO 3000 /* interrupt timeout in jiffies */ | ||
164 | #define PT_SPIN_DEL 50 /* spin delay in micro-seconds */ | ||
165 | #define PT_RESET_TMO 30 /* 30 seconds */ | ||
166 | #define PT_READY_TMO 60 /* 60 seconds */ | ||
167 | #define PT_REWIND_TMO 1200 /* 20 minutes */ | ||
168 | |||
169 | #define PT_SPIN ((1000000/(HZ*PT_SPIN_DEL))*PT_TMO) | ||
170 | |||
171 | #define STAT_ERR 0x00001 | ||
172 | #define STAT_INDEX 0x00002 | ||
173 | #define STAT_ECC 0x00004 | ||
174 | #define STAT_DRQ 0x00008 | ||
175 | #define STAT_SEEK 0x00010 | ||
176 | #define STAT_WRERR 0x00020 | ||
177 | #define STAT_READY 0x00040 | ||
178 | #define STAT_BUSY 0x00080 | ||
179 | #define STAT_SENSE 0x1f000 | ||
180 | |||
181 | #define ATAPI_TEST_READY 0x00 | ||
182 | #define ATAPI_REWIND 0x01 | ||
183 | #define ATAPI_REQ_SENSE 0x03 | ||
184 | #define ATAPI_READ_6 0x08 | ||
185 | #define ATAPI_WRITE_6 0x0a | ||
186 | #define ATAPI_WFM 0x10 | ||
187 | #define ATAPI_IDENTIFY 0x12 | ||
188 | #define ATAPI_MODE_SENSE 0x1a | ||
189 | #define ATAPI_LOG_SENSE 0x4d | ||
190 | |||
191 | static int pt_open(struct inode *inode, struct file *file); | ||
192 | static int pt_ioctl(struct inode *inode, struct file *file, | ||
193 | unsigned int cmd, unsigned long arg); | ||
194 | static int pt_release(struct inode *inode, struct file *file); | ||
195 | static ssize_t pt_read(struct file *filp, char __user *buf, | ||
196 | size_t count, loff_t * ppos); | ||
197 | static ssize_t pt_write(struct file *filp, const char __user *buf, | ||
198 | size_t count, loff_t * ppos); | ||
199 | static int pt_detect(void); | ||
200 | |||
201 | /* bits in tape->flags */ | ||
202 | |||
203 | #define PT_MEDIA 1 | ||
204 | #define PT_WRITE_OK 2 | ||
205 | #define PT_REWIND 4 | ||
206 | #define PT_WRITING 8 | ||
207 | #define PT_READING 16 | ||
208 | #define PT_EOF 32 | ||
209 | |||
210 | #define PT_NAMELEN 8 | ||
211 | #define PT_BUFSIZE 16384 | ||
212 | |||
213 | struct pt_unit { | ||
214 | struct pi_adapter pia; /* interface to paride layer */ | ||
215 | struct pi_adapter *pi; | ||
216 | int flags; /* various state flags */ | ||
217 | int last_sense; /* result of last request sense */ | ||
218 | int drive; /* drive */ | ||
219 | atomic_t available; /* 1 if access is available 0 otherwise */ | ||
220 | int bs; /* block size */ | ||
221 | int capacity; /* Size of tape in KB */ | ||
222 | int present; /* device present ? */ | ||
223 | char *bufptr; | ||
224 | char name[PT_NAMELEN]; /* pf0, pf1, ... */ | ||
225 | }; | ||
226 | |||
227 | static int pt_identify(struct pt_unit *tape); | ||
228 | |||
229 | static struct pt_unit pt[PT_UNITS]; | ||
230 | |||
231 | static char pt_scratch[512]; /* scratch block buffer */ | ||
232 | |||
233 | /* kernel glue structures */ | ||
234 | |||
235 | static struct file_operations pt_fops = { | ||
236 | .owner = THIS_MODULE, | ||
237 | .read = pt_read, | ||
238 | .write = pt_write, | ||
239 | .ioctl = pt_ioctl, | ||
240 | .open = pt_open, | ||
241 | .release = pt_release, | ||
242 | }; | ||
243 | |||
244 | /* sysfs class support */ | ||
245 | static struct class_simple *pt_class; | ||
246 | |||
247 | static inline int status_reg(struct pi_adapter *pi) | ||
248 | { | ||
249 | return pi_read_regr(pi, 1, 6); | ||
250 | } | ||
251 | |||
252 | static inline int read_reg(struct pi_adapter *pi, int reg) | ||
253 | { | ||
254 | return pi_read_regr(pi, 0, reg); | ||
255 | } | ||
256 | |||
257 | static inline void write_reg(struct pi_adapter *pi, int reg, int val) | ||
258 | { | ||
259 | pi_write_regr(pi, 0, reg, val); | ||
260 | } | ||
261 | |||
262 | static inline u8 DRIVE(struct pt_unit *tape) | ||
263 | { | ||
264 | return 0xa0+0x10*tape->drive; | ||
265 | } | ||
266 | |||
267 | static int pt_wait(struct pt_unit *tape, int go, int stop, char *fun, char *msg) | ||
268 | { | ||
269 | int j, r, e, s, p; | ||
270 | struct pi_adapter *pi = tape->pi; | ||
271 | |||
272 | j = 0; | ||
273 | while ((((r = status_reg(pi)) & go) || (stop && (!(r & stop)))) | ||
274 | && (j++ < PT_SPIN)) | ||
275 | udelay(PT_SPIN_DEL); | ||
276 | |||
277 | if ((r & (STAT_ERR & stop)) || (j >= PT_SPIN)) { | ||
278 | s = read_reg(pi, 7); | ||
279 | e = read_reg(pi, 1); | ||
280 | p = read_reg(pi, 2); | ||
281 | if (j >= PT_SPIN) | ||
282 | e |= 0x100; | ||
283 | if (fun) | ||
284 | printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x" | ||
285 | " loop=%d phase=%d\n", | ||
286 | tape->name, fun, msg, r, s, e, j, p); | ||
287 | return (e << 8) + s; | ||
288 | } | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int pt_command(struct pt_unit *tape, char *cmd, int dlen, char *fun) | ||
293 | { | ||
294 | struct pi_adapter *pi = tape->pi; | ||
295 | pi_connect(pi); | ||
296 | |||
297 | write_reg(pi, 6, DRIVE(tape)); | ||
298 | |||
299 | if (pt_wait(tape, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) { | ||
300 | pi_disconnect(pi); | ||
301 | return -1; | ||
302 | } | ||
303 | |||
304 | write_reg(pi, 4, dlen % 256); | ||
305 | write_reg(pi, 5, dlen / 256); | ||
306 | write_reg(pi, 7, 0xa0); /* ATAPI packet command */ | ||
307 | |||
308 | if (pt_wait(tape, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) { | ||
309 | pi_disconnect(pi); | ||
310 | return -1; | ||
311 | } | ||
312 | |||
313 | if (read_reg(pi, 2) != 1) { | ||
314 | printk("%s: %s: command phase error\n", tape->name, fun); | ||
315 | pi_disconnect(pi); | ||
316 | return -1; | ||
317 | } | ||
318 | |||
319 | pi_write_block(pi, cmd, 12); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int pt_completion(struct pt_unit *tape, char *buf, char *fun) | ||
325 | { | ||
326 | struct pi_adapter *pi = tape->pi; | ||
327 | int r, s, n, p; | ||
328 | |||
329 | r = pt_wait(tape, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR, | ||
330 | fun, "completion"); | ||
331 | |||
332 | if (read_reg(pi, 7) & STAT_DRQ) { | ||
333 | n = (((read_reg(pi, 4) + 256 * read_reg(pi, 5)) + | ||
334 | 3) & 0xfffc); | ||
335 | p = read_reg(pi, 2) & 3; | ||
336 | if (p == 0) | ||
337 | pi_write_block(pi, buf, n); | ||
338 | if (p == 2) | ||
339 | pi_read_block(pi, buf, n); | ||
340 | } | ||
341 | |||
342 | s = pt_wait(tape, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done"); | ||
343 | |||
344 | pi_disconnect(pi); | ||
345 | |||
346 | return (r ? r : s); | ||
347 | } | ||
348 | |||
349 | static void pt_req_sense(struct pt_unit *tape, int quiet) | ||
350 | { | ||
351 | char rs_cmd[12] = { ATAPI_REQ_SENSE, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 }; | ||
352 | char buf[16]; | ||
353 | int r; | ||
354 | |||
355 | r = pt_command(tape, rs_cmd, 16, "Request sense"); | ||
356 | mdelay(1); | ||
357 | if (!r) | ||
358 | pt_completion(tape, buf, "Request sense"); | ||
359 | |||
360 | tape->last_sense = -1; | ||
361 | if (!r) { | ||
362 | if (!quiet) | ||
363 | printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n", | ||
364 | tape->name, buf[2] & 0xf, buf[12], buf[13]); | ||
365 | tape->last_sense = (buf[2] & 0xf) | ((buf[12] & 0xff) << 8) | ||
366 | | ((buf[13] & 0xff) << 16); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | static int pt_atapi(struct pt_unit *tape, char *cmd, int dlen, char *buf, char *fun) | ||
371 | { | ||
372 | int r; | ||
373 | |||
374 | r = pt_command(tape, cmd, dlen, fun); | ||
375 | mdelay(1); | ||
376 | if (!r) | ||
377 | r = pt_completion(tape, buf, fun); | ||
378 | if (r) | ||
379 | pt_req_sense(tape, !fun); | ||
380 | |||
381 | return r; | ||
382 | } | ||
383 | |||
384 | static void pt_sleep(int cs) | ||
385 | { | ||
386 | current->state = TASK_INTERRUPTIBLE; | ||
387 | schedule_timeout(cs); | ||
388 | } | ||
389 | |||
390 | static int pt_poll_dsc(struct pt_unit *tape, int pause, int tmo, char *msg) | ||
391 | { | ||
392 | struct pi_adapter *pi = tape->pi; | ||
393 | int k, e, s; | ||
394 | |||
395 | k = 0; | ||
396 | e = 0; | ||
397 | s = 0; | ||
398 | while (k < tmo) { | ||
399 | pt_sleep(pause); | ||
400 | k++; | ||
401 | pi_connect(pi); | ||
402 | write_reg(pi, 6, DRIVE(tape)); | ||
403 | s = read_reg(pi, 7); | ||
404 | e = read_reg(pi, 1); | ||
405 | pi_disconnect(pi); | ||
406 | if (s & (STAT_ERR | STAT_SEEK)) | ||
407 | break; | ||
408 | } | ||
409 | if ((k >= tmo) || (s & STAT_ERR)) { | ||
410 | if (k >= tmo) | ||
411 | printk("%s: %s DSC timeout\n", tape->name, msg); | ||
412 | else | ||
413 | printk("%s: %s stat=0x%x err=0x%x\n", tape->name, msg, s, | ||
414 | e); | ||
415 | pt_req_sense(tape, 0); | ||
416 | return 0; | ||
417 | } | ||
418 | return 1; | ||
419 | } | ||
420 | |||
421 | static void pt_media_access_cmd(struct pt_unit *tape, int tmo, char *cmd, char *fun) | ||
422 | { | ||
423 | if (pt_command(tape, cmd, 0, fun)) { | ||
424 | pt_req_sense(tape, 0); | ||
425 | return; | ||
426 | } | ||
427 | pi_disconnect(tape->pi); | ||
428 | pt_poll_dsc(tape, HZ, tmo, fun); | ||
429 | } | ||
430 | |||
431 | static void pt_rewind(struct pt_unit *tape) | ||
432 | { | ||
433 | char rw_cmd[12] = { ATAPI_REWIND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
434 | |||
435 | pt_media_access_cmd(tape, PT_REWIND_TMO, rw_cmd, "rewind"); | ||
436 | } | ||
437 | |||
438 | static void pt_write_fm(struct pt_unit *tape) | ||
439 | { | ||
440 | char wm_cmd[12] = { ATAPI_WFM, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }; | ||
441 | |||
442 | pt_media_access_cmd(tape, PT_TMO, wm_cmd, "write filemark"); | ||
443 | } | ||
444 | |||
445 | #define DBMSG(msg) ((verbose>1)?(msg):NULL) | ||
446 | |||
447 | static int pt_reset(struct pt_unit *tape) | ||
448 | { | ||
449 | struct pi_adapter *pi = tape->pi; | ||
450 | int i, k, flg; | ||
451 | int expect[5] = { 1, 1, 1, 0x14, 0xeb }; | ||
452 | |||
453 | pi_connect(pi); | ||
454 | write_reg(pi, 6, DRIVE(tape)); | ||
455 | write_reg(pi, 7, 8); | ||
456 | |||
457 | pt_sleep(20 * HZ / 1000); | ||
458 | |||
459 | k = 0; | ||
460 | while ((k++ < PT_RESET_TMO) && (status_reg(pi) & STAT_BUSY)) | ||
461 | pt_sleep(HZ / 10); | ||
462 | |||
463 | flg = 1; | ||
464 | for (i = 0; i < 5; i++) | ||
465 | flg &= (read_reg(pi, i + 1) == expect[i]); | ||
466 | |||
467 | if (verbose) { | ||
468 | printk("%s: Reset (%d) signature = ", tape->name, k); | ||
469 | for (i = 0; i < 5; i++) | ||
470 | printk("%3x", read_reg(pi, i + 1)); | ||
471 | if (!flg) | ||
472 | printk(" (incorrect)"); | ||
473 | printk("\n"); | ||
474 | } | ||
475 | |||
476 | pi_disconnect(pi); | ||
477 | return flg - 1; | ||
478 | } | ||
479 | |||
480 | static int pt_ready_wait(struct pt_unit *tape, int tmo) | ||
481 | { | ||
482 | char tr_cmd[12] = { ATAPI_TEST_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
483 | int k, p; | ||
484 | |||
485 | k = 0; | ||
486 | while (k < tmo) { | ||
487 | tape->last_sense = 0; | ||
488 | pt_atapi(tape, tr_cmd, 0, NULL, DBMSG("test unit ready")); | ||
489 | p = tape->last_sense; | ||
490 | if (!p) | ||
491 | return 0; | ||
492 | if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6))) | ||
493 | return p; | ||
494 | k++; | ||
495 | pt_sleep(HZ); | ||
496 | } | ||
497 | return 0x000020; /* timeout */ | ||
498 | } | ||
499 | |||
500 | static void xs(char *buf, char *targ, int offs, int len) | ||
501 | { | ||
502 | int j, k, l; | ||
503 | |||
504 | j = 0; | ||
505 | l = 0; | ||
506 | for (k = 0; k < len; k++) | ||
507 | if ((buf[k + offs] != 0x20) || (buf[k + offs] != l)) | ||
508 | l = targ[j++] = buf[k + offs]; | ||
509 | if (l == 0x20) | ||
510 | j--; | ||
511 | targ[j] = 0; | ||
512 | } | ||
513 | |||
514 | static int xn(char *buf, int offs, int size) | ||
515 | { | ||
516 | int v, k; | ||
517 | |||
518 | v = 0; | ||
519 | for (k = 0; k < size; k++) | ||
520 | v = v * 256 + (buf[k + offs] & 0xff); | ||
521 | return v; | ||
522 | } | ||
523 | |||
524 | static int pt_identify(struct pt_unit *tape) | ||
525 | { | ||
526 | int dt, s; | ||
527 | char *ms[2] = { "master", "slave" }; | ||
528 | char mf[10], id[18]; | ||
529 | char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; | ||
530 | char ms_cmd[12] = | ||
531 | { ATAPI_MODE_SENSE, 0, 0x2a, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; | ||
532 | char ls_cmd[12] = | ||
533 | { ATAPI_LOG_SENSE, 0, 0x71, 0, 0, 0, 0, 0, 36, 0, 0, 0 }; | ||
534 | char buf[36]; | ||
535 | |||
536 | s = pt_atapi(tape, id_cmd, 36, buf, "identify"); | ||
537 | if (s) | ||
538 | return -1; | ||
539 | |||
540 | dt = buf[0] & 0x1f; | ||
541 | if (dt != 1) { | ||
542 | if (verbose) | ||
543 | printk("%s: Drive %d, unsupported type %d\n", | ||
544 | tape->name, tape->drive, dt); | ||
545 | return -1; | ||
546 | } | ||
547 | |||
548 | xs(buf, mf, 8, 8); | ||
549 | xs(buf, id, 16, 16); | ||
550 | |||
551 | tape->flags = 0; | ||
552 | tape->capacity = 0; | ||
553 | tape->bs = 0; | ||
554 | |||
555 | if (!pt_ready_wait(tape, PT_READY_TMO)) | ||
556 | tape->flags |= PT_MEDIA; | ||
557 | |||
558 | if (!pt_atapi(tape, ms_cmd, 36, buf, "mode sense")) { | ||
559 | if (!(buf[2] & 0x80)) | ||
560 | tape->flags |= PT_WRITE_OK; | ||
561 | tape->bs = xn(buf, 10, 2); | ||
562 | } | ||
563 | |||
564 | if (!pt_atapi(tape, ls_cmd, 36, buf, "log sense")) | ||
565 | tape->capacity = xn(buf, 24, 4); | ||
566 | |||
567 | printk("%s: %s %s, %s", tape->name, mf, id, ms[tape->drive]); | ||
568 | if (!(tape->flags & PT_MEDIA)) | ||
569 | printk(", no media\n"); | ||
570 | else { | ||
571 | if (!(tape->flags & PT_WRITE_OK)) | ||
572 | printk(", RO"); | ||
573 | printk(", blocksize %d, %d MB\n", tape->bs, tape->capacity / 1024); | ||
574 | } | ||
575 | |||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | |||
580 | /* | ||
581 | * returns 0, with id set if drive is detected | ||
582 | * -1, if drive detection failed | ||
583 | */ | ||
584 | static int pt_probe(struct pt_unit *tape) | ||
585 | { | ||
586 | if (tape->drive == -1) { | ||
587 | for (tape->drive = 0; tape->drive <= 1; tape->drive++) | ||
588 | if (!pt_reset(tape)) | ||
589 | return pt_identify(tape); | ||
590 | } else { | ||
591 | if (!pt_reset(tape)) | ||
592 | return pt_identify(tape); | ||
593 | } | ||
594 | return -1; | ||
595 | } | ||
596 | |||
597 | static int pt_detect(void) | ||
598 | { | ||
599 | struct pt_unit *tape; | ||
600 | int specified = 0, found = 0; | ||
601 | int unit; | ||
602 | |||
603 | printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major); | ||
604 | |||
605 | specified = 0; | ||
606 | for (unit = 0; unit < PT_UNITS; unit++) { | ||
607 | struct pt_unit *tape = &pt[unit]; | ||
608 | tape->pi = &tape->pia; | ||
609 | atomic_set(&tape->available, 1); | ||
610 | tape->flags = 0; | ||
611 | tape->last_sense = 0; | ||
612 | tape->present = 0; | ||
613 | tape->bufptr = NULL; | ||
614 | tape->drive = DU[D_SLV]; | ||
615 | snprintf(tape->name, PT_NAMELEN, "%s%d", name, unit); | ||
616 | if (!DU[D_PRT]) | ||
617 | continue; | ||
618 | specified++; | ||
619 | if (pi_init(tape->pi, 0, DU[D_PRT], DU[D_MOD], DU[D_UNI], | ||
620 | DU[D_PRO], DU[D_DLY], pt_scratch, PI_PT, | ||
621 | verbose, tape->name)) { | ||
622 | if (!pt_probe(tape)) { | ||
623 | tape->present = 1; | ||
624 | found++; | ||
625 | } else | ||
626 | pi_release(tape->pi); | ||
627 | } | ||
628 | } | ||
629 | if (specified == 0) { | ||
630 | tape = pt; | ||
631 | if (pi_init(tape->pi, 1, -1, -1, -1, -1, -1, pt_scratch, | ||
632 | PI_PT, verbose, tape->name)) { | ||
633 | if (!pt_probe(tape)) { | ||
634 | tape->present = 1; | ||
635 | found++; | ||
636 | } else | ||
637 | pi_release(tape->pi); | ||
638 | } | ||
639 | |||
640 | } | ||
641 | if (found) | ||
642 | return 0; | ||
643 | |||
644 | printk("%s: No ATAPI tape drive detected\n", name); | ||
645 | return -1; | ||
646 | } | ||
647 | |||
648 | static int pt_open(struct inode *inode, struct file *file) | ||
649 | { | ||
650 | int unit = iminor(inode) & 0x7F; | ||
651 | struct pt_unit *tape = pt + unit; | ||
652 | int err; | ||
653 | |||
654 | if (unit >= PT_UNITS || (!tape->present)) | ||
655 | return -ENODEV; | ||
656 | |||
657 | err = -EBUSY; | ||
658 | if (!atomic_dec_and_test(&tape->available)) | ||
659 | goto out; | ||
660 | |||
661 | pt_identify(tape); | ||
662 | |||
663 | err = -ENODEV; | ||
664 | if (!tape->flags & PT_MEDIA) | ||
665 | goto out; | ||
666 | |||
667 | err = -EROFS; | ||
668 | if ((!tape->flags & PT_WRITE_OK) && (file->f_mode & 2)) | ||
669 | goto out; | ||
670 | |||
671 | if (!(iminor(inode) & 128)) | ||
672 | tape->flags |= PT_REWIND; | ||
673 | |||
674 | err = -ENOMEM; | ||
675 | tape->bufptr = kmalloc(PT_BUFSIZE, GFP_KERNEL); | ||
676 | if (tape->bufptr == NULL) { | ||
677 | printk("%s: buffer allocation failed\n", tape->name); | ||
678 | goto out; | ||
679 | } | ||
680 | |||
681 | file->private_data = tape; | ||
682 | return 0; | ||
683 | |||
684 | out: | ||
685 | atomic_inc(&tape->available); | ||
686 | return err; | ||
687 | } | ||
688 | |||
689 | static int pt_ioctl(struct inode *inode, struct file *file, | ||
690 | unsigned int cmd, unsigned long arg) | ||
691 | { | ||
692 | struct pt_unit *tape = file->private_data; | ||
693 | struct mtop __user *p = (void __user *)arg; | ||
694 | struct mtop mtop; | ||
695 | |||
696 | switch (cmd) { | ||
697 | case MTIOCTOP: | ||
698 | if (copy_from_user(&mtop, p, sizeof(struct mtop))) | ||
699 | return -EFAULT; | ||
700 | |||
701 | switch (mtop.mt_op) { | ||
702 | |||
703 | case MTREW: | ||
704 | pt_rewind(tape); | ||
705 | return 0; | ||
706 | |||
707 | case MTWEOF: | ||
708 | pt_write_fm(tape); | ||
709 | return 0; | ||
710 | |||
711 | default: | ||
712 | printk("%s: Unimplemented mt_op %d\n", tape->name, | ||
713 | mtop.mt_op); | ||
714 | return -EINVAL; | ||
715 | } | ||
716 | |||
717 | default: | ||
718 | printk("%s: Unimplemented ioctl 0x%x\n", tape->name, cmd); | ||
719 | return -EINVAL; | ||
720 | |||
721 | } | ||
722 | } | ||
723 | |||
724 | static int | ||
725 | pt_release(struct inode *inode, struct file *file) | ||
726 | { | ||
727 | struct pt_unit *tape = file->private_data; | ||
728 | |||
729 | if (atomic_read(&tape->available) > 1) | ||
730 | return -EINVAL; | ||
731 | |||
732 | if (tape->flags & PT_WRITING) | ||
733 | pt_write_fm(tape); | ||
734 | |||
735 | if (tape->flags & PT_REWIND) | ||
736 | pt_rewind(tape); | ||
737 | |||
738 | kfree(tape->bufptr); | ||
739 | tape->bufptr = NULL; | ||
740 | |||
741 | atomic_inc(&tape->available); | ||
742 | |||
743 | return 0; | ||
744 | |||
745 | } | ||
746 | |||
747 | static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) | ||
748 | { | ||
749 | struct pt_unit *tape = filp->private_data; | ||
750 | struct pi_adapter *pi = tape->pi; | ||
751 | char rd_cmd[12] = { ATAPI_READ_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
752 | int k, n, r, p, s, t, b; | ||
753 | |||
754 | if (!(tape->flags & (PT_READING | PT_WRITING))) { | ||
755 | tape->flags |= PT_READING; | ||
756 | if (pt_atapi(tape, rd_cmd, 0, NULL, "start read-ahead")) | ||
757 | return -EIO; | ||
758 | } else if (tape->flags & PT_WRITING) | ||
759 | return -EIO; | ||
760 | |||
761 | if (tape->flags & PT_EOF) | ||
762 | return 0; | ||
763 | |||
764 | t = 0; | ||
765 | |||
766 | while (count > 0) { | ||
767 | |||
768 | if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "read")) | ||
769 | return -EIO; | ||
770 | |||
771 | n = count; | ||
772 | if (n > 32768) | ||
773 | n = 32768; /* max per command */ | ||
774 | b = (n - 1 + tape->bs) / tape->bs; | ||
775 | n = b * tape->bs; /* rounded up to even block */ | ||
776 | |||
777 | rd_cmd[4] = b; | ||
778 | |||
779 | r = pt_command(tape, rd_cmd, n, "read"); | ||
780 | |||
781 | mdelay(1); | ||
782 | |||
783 | if (r) { | ||
784 | pt_req_sense(tape, 0); | ||
785 | return -EIO; | ||
786 | } | ||
787 | |||
788 | while (1) { | ||
789 | |||
790 | r = pt_wait(tape, STAT_BUSY, | ||
791 | STAT_DRQ | STAT_ERR | STAT_READY, | ||
792 | DBMSG("read DRQ"), ""); | ||
793 | |||
794 | if (r & STAT_SENSE) { | ||
795 | pi_disconnect(pi); | ||
796 | pt_req_sense(tape, 0); | ||
797 | return -EIO; | ||
798 | } | ||
799 | |||
800 | if (r) | ||
801 | tape->flags |= PT_EOF; | ||
802 | |||
803 | s = read_reg(pi, 7); | ||
804 | |||
805 | if (!(s & STAT_DRQ)) | ||
806 | break; | ||
807 | |||
808 | n = (read_reg(pi, 4) + 256 * read_reg(pi, 5)); | ||
809 | p = (read_reg(pi, 2) & 3); | ||
810 | if (p != 2) { | ||
811 | pi_disconnect(pi); | ||
812 | printk("%s: Phase error on read: %d\n", tape->name, | ||
813 | p); | ||
814 | return -EIO; | ||
815 | } | ||
816 | |||
817 | while (n > 0) { | ||
818 | k = n; | ||
819 | if (k > PT_BUFSIZE) | ||
820 | k = PT_BUFSIZE; | ||
821 | pi_read_block(pi, tape->bufptr, k); | ||
822 | n -= k; | ||
823 | b = k; | ||
824 | if (b > count) | ||
825 | b = count; | ||
826 | if (copy_to_user(buf + t, tape->bufptr, b)) { | ||
827 | pi_disconnect(pi); | ||
828 | return -EFAULT; | ||
829 | } | ||
830 | t += b; | ||
831 | count -= b; | ||
832 | } | ||
833 | |||
834 | } | ||
835 | pi_disconnect(pi); | ||
836 | if (tape->flags & PT_EOF) | ||
837 | break; | ||
838 | } | ||
839 | |||
840 | return t; | ||
841 | |||
842 | } | ||
843 | |||
844 | static ssize_t pt_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) | ||
845 | { | ||
846 | struct pt_unit *tape = filp->private_data; | ||
847 | struct pi_adapter *pi = tape->pi; | ||
848 | char wr_cmd[12] = { ATAPI_WRITE_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
849 | int k, n, r, p, s, t, b; | ||
850 | |||
851 | if (!(tape->flags & PT_WRITE_OK)) | ||
852 | return -EROFS; | ||
853 | |||
854 | if (!(tape->flags & (PT_READING | PT_WRITING))) { | ||
855 | tape->flags |= PT_WRITING; | ||
856 | if (pt_atapi | ||
857 | (tape, wr_cmd, 0, NULL, "start buffer-available mode")) | ||
858 | return -EIO; | ||
859 | } else if (tape->flags & PT_READING) | ||
860 | return -EIO; | ||
861 | |||
862 | if (tape->flags & PT_EOF) | ||
863 | return -ENOSPC; | ||
864 | |||
865 | t = 0; | ||
866 | |||
867 | while (count > 0) { | ||
868 | |||
869 | if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "write")) | ||
870 | return -EIO; | ||
871 | |||
872 | n = count; | ||
873 | if (n > 32768) | ||
874 | n = 32768; /* max per command */ | ||
875 | b = (n - 1 + tape->bs) / tape->bs; | ||
876 | n = b * tape->bs; /* rounded up to even block */ | ||
877 | |||
878 | wr_cmd[4] = b; | ||
879 | |||
880 | r = pt_command(tape, wr_cmd, n, "write"); | ||
881 | |||
882 | mdelay(1); | ||
883 | |||
884 | if (r) { /* error delivering command only */ | ||
885 | pt_req_sense(tape, 0); | ||
886 | return -EIO; | ||
887 | } | ||
888 | |||
889 | while (1) { | ||
890 | |||
891 | r = pt_wait(tape, STAT_BUSY, | ||
892 | STAT_DRQ | STAT_ERR | STAT_READY, | ||
893 | DBMSG("write DRQ"), NULL); | ||
894 | |||
895 | if (r & STAT_SENSE) { | ||
896 | pi_disconnect(pi); | ||
897 | pt_req_sense(tape, 0); | ||
898 | return -EIO; | ||
899 | } | ||
900 | |||
901 | if (r) | ||
902 | tape->flags |= PT_EOF; | ||
903 | |||
904 | s = read_reg(pi, 7); | ||
905 | |||
906 | if (!(s & STAT_DRQ)) | ||
907 | break; | ||
908 | |||
909 | n = (read_reg(pi, 4) + 256 * read_reg(pi, 5)); | ||
910 | p = (read_reg(pi, 2) & 3); | ||
911 | if (p != 0) { | ||
912 | pi_disconnect(pi); | ||
913 | printk("%s: Phase error on write: %d \n", | ||
914 | tape->name, p); | ||
915 | return -EIO; | ||
916 | } | ||
917 | |||
918 | while (n > 0) { | ||
919 | k = n; | ||
920 | if (k > PT_BUFSIZE) | ||
921 | k = PT_BUFSIZE; | ||
922 | b = k; | ||
923 | if (b > count) | ||
924 | b = count; | ||
925 | if (copy_from_user(tape->bufptr, buf + t, b)) { | ||
926 | pi_disconnect(pi); | ||
927 | return -EFAULT; | ||
928 | } | ||
929 | pi_write_block(pi, tape->bufptr, k); | ||
930 | t += b; | ||
931 | count -= b; | ||
932 | n -= k; | ||
933 | } | ||
934 | |||
935 | } | ||
936 | pi_disconnect(pi); | ||
937 | if (tape->flags & PT_EOF) | ||
938 | break; | ||
939 | } | ||
940 | |||
941 | return t; | ||
942 | } | ||
943 | |||
944 | static int __init pt_init(void) | ||
945 | { | ||
946 | int unit, err = 0; | ||
947 | |||
948 | if (disable) { | ||
949 | err = -1; | ||
950 | goto out; | ||
951 | } | ||
952 | |||
953 | if (pt_detect()) { | ||
954 | err = -1; | ||
955 | goto out; | ||
956 | } | ||
957 | |||
958 | if (register_chrdev(major, name, &pt_fops)) { | ||
959 | printk("pt_init: unable to get major number %d\n", major); | ||
960 | for (unit = 0; unit < PT_UNITS; unit++) | ||
961 | if (pt[unit].present) | ||
962 | pi_release(pt[unit].pi); | ||
963 | err = -1; | ||
964 | goto out; | ||
965 | } | ||
966 | pt_class = class_simple_create(THIS_MODULE, "pt"); | ||
967 | if (IS_ERR(pt_class)) { | ||
968 | err = PTR_ERR(pt_class); | ||
969 | goto out_chrdev; | ||
970 | } | ||
971 | |||
972 | devfs_mk_dir("pt"); | ||
973 | for (unit = 0; unit < PT_UNITS; unit++) | ||
974 | if (pt[unit].present) { | ||
975 | class_simple_device_add(pt_class, MKDEV(major, unit), | ||
976 | NULL, "pt%d", unit); | ||
977 | err = devfs_mk_cdev(MKDEV(major, unit), | ||
978 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
979 | "pt/%d", unit); | ||
980 | if (err) { | ||
981 | class_simple_device_remove(MKDEV(major, unit)); | ||
982 | goto out_class; | ||
983 | } | ||
984 | class_simple_device_add(pt_class, MKDEV(major, unit + 128), | ||
985 | NULL, "pt%dn", unit); | ||
986 | err = devfs_mk_cdev(MKDEV(major, unit + 128), | ||
987 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
988 | "pt/%dn", unit); | ||
989 | if (err) { | ||
990 | class_simple_device_remove(MKDEV(major, unit + 128)); | ||
991 | goto out_class; | ||
992 | } | ||
993 | } | ||
994 | goto out; | ||
995 | |||
996 | out_class: | ||
997 | class_simple_destroy(pt_class); | ||
998 | out_chrdev: | ||
999 | unregister_chrdev(major, "pt"); | ||
1000 | out: | ||
1001 | return err; | ||
1002 | } | ||
1003 | |||
1004 | static void __exit pt_exit(void) | ||
1005 | { | ||
1006 | int unit; | ||
1007 | for (unit = 0; unit < PT_UNITS; unit++) | ||
1008 | if (pt[unit].present) { | ||
1009 | class_simple_device_remove(MKDEV(major, unit)); | ||
1010 | devfs_remove("pt/%d", unit); | ||
1011 | class_simple_device_remove(MKDEV(major, unit + 128)); | ||
1012 | devfs_remove("pt/%dn", unit); | ||
1013 | } | ||
1014 | class_simple_destroy(pt_class); | ||
1015 | devfs_remove("pt"); | ||
1016 | unregister_chrdev(major, name); | ||
1017 | for (unit = 0; unit < PT_UNITS; unit++) | ||
1018 | if (pt[unit].present) | ||
1019 | pi_release(pt[unit].pi); | ||
1020 | } | ||
1021 | |||
1022 | MODULE_LICENSE("GPL"); | ||
1023 | module_init(pt_init) | ||
1024 | module_exit(pt_exit) | ||