diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-27 01:25:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-29 05:13:08 -0400 |
commit | 902663f6ea4a2603bee0d88450aae2d653a46f5d (patch) | |
tree | d085c52ce6569c08c90ebfcf23871eed7bcedc3d /drivers/sbus/char/bpp.c | |
parent | 51e0f004a9ab9104acbe323c0b20e0279bf9be85 (diff) |
sparc: Delete bare sbus char bpp driver, obsoleted by parport_sunbpp
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/sbus/char/bpp.c')
-rw-r--r-- | drivers/sbus/char/bpp.c | 1055 |
1 files changed, 0 insertions, 1055 deletions
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c deleted file mode 100644 index bba21e053a1b..000000000000 --- a/drivers/sbus/char/bpp.c +++ /dev/null | |||
@@ -1,1055 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/sbus/char/bpp.c | ||
3 | * | ||
4 | * Copyright (c) 1995 Picture Elements | ||
5 | * Stephen Williams (steve@icarus.com) | ||
6 | * Gus Baldauf (gbaldauf@ix.netcom.com) | ||
7 | * | ||
8 | * Linux/SPARC port by Peter Zaitcev. | ||
9 | * Integration into SPARC tree by Tom Dyas. | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/ioport.h> | ||
21 | #include <linux/major.h> | ||
22 | #include <linux/smp_lock.h> | ||
23 | |||
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/io.h> | ||
26 | |||
27 | #if defined(__i386__) | ||
28 | # include <asm/system.h> | ||
29 | #endif | ||
30 | |||
31 | #if defined(__sparc__) | ||
32 | # include <linux/init.h> | ||
33 | # include <linux/delay.h> /* udelay() */ | ||
34 | |||
35 | # include <asm/oplib.h> /* OpenProm Library */ | ||
36 | # include <asm/sbus.h> | ||
37 | #endif | ||
38 | |||
39 | #include <asm/bpp.h> | ||
40 | |||
41 | #define BPP_PROBE_CODE 0x55 | ||
42 | #define BPP_DELAY 100 | ||
43 | |||
44 | static const unsigned BPP_MAJOR = LP_MAJOR; | ||
45 | static const char *bpp_dev_name = "bpp"; | ||
46 | |||
47 | /* When switching from compatibility to a mode where I can read, try | ||
48 | the following mode first. */ | ||
49 | |||
50 | /* const unsigned char DEFAULT_ECP = 0x10; */ | ||
51 | static const unsigned char DEFAULT_ECP = 0x30; | ||
52 | static const unsigned char DEFAULT_NIBBLE = 0x00; | ||
53 | |||
54 | /* | ||
55 | * These are 1284 time constraints, in units of jiffies. | ||
56 | */ | ||
57 | |||
58 | static const unsigned long TIME_PSetup = 1; | ||
59 | static const unsigned long TIME_PResponse = 6; | ||
60 | static const unsigned long TIME_IDLE_LIMIT = 2000; | ||
61 | |||
62 | /* | ||
63 | * One instance per supported subdevice... | ||
64 | */ | ||
65 | # define BPP_NO 3 | ||
66 | |||
67 | enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP }; | ||
68 | |||
69 | struct inst { | ||
70 | unsigned present : 1; /* True if the hardware exists */ | ||
71 | unsigned enhanced : 1; /* True if the hardware in "enhanced" */ | ||
72 | unsigned opened : 1; /* True if the device is opened already */ | ||
73 | unsigned run_flag : 1; /* True if waiting for a repeate byte */ | ||
74 | |||
75 | unsigned char direction; /* 0 --> out, 0x20 --> IN */ | ||
76 | unsigned char pp_state; /* State of host controlled pins. */ | ||
77 | enum IEEE_Mode mode; | ||
78 | |||
79 | unsigned char run_length; | ||
80 | unsigned char repeat_byte; | ||
81 | }; | ||
82 | |||
83 | static struct inst instances[BPP_NO]; | ||
84 | |||
85 | #if defined(__i386__) | ||
86 | |||
87 | static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc }; | ||
88 | |||
89 | /* | ||
90 | * These are for data access. | ||
91 | * Control lines accesses are hidden in set_bits() and get_bits(). | ||
92 | * The exception is the probe procedure, which is system-dependent. | ||
93 | */ | ||
94 | #define bpp_outb_p(data, base) outb_p((data), (base)) | ||
95 | #define bpp_inb(base) inb(base) | ||
96 | #define bpp_inb_p(base) inb_p(base) | ||
97 | |||
98 | /* | ||
99 | * This method takes the pin values mask and sets the hardware pins to | ||
100 | * the requested value: 1 == high voltage, 0 == low voltage. This | ||
101 | * burries the annoying PC bit inversion and preserves the direction | ||
102 | * flag. | ||
103 | */ | ||
104 | static void set_pins(unsigned short pins, unsigned minor) | ||
105 | { | ||
106 | unsigned char bits = instances[minor].direction; /* == 0x20 */ | ||
107 | |||
108 | if (! (pins & BPP_PP_nStrobe)) bits |= 1; | ||
109 | if (! (pins & BPP_PP_nAutoFd)) bits |= 2; | ||
110 | if ( pins & BPP_PP_nInit) bits |= 4; | ||
111 | if (! (pins & BPP_PP_nSelectIn)) bits |= 8; | ||
112 | |||
113 | instances[minor].pp_state = bits; | ||
114 | |||
115 | outb_p(bits, base_addrs[minor]+2); | ||
116 | } | ||
117 | |||
118 | static unsigned short get_pins(unsigned minor) | ||
119 | { | ||
120 | unsigned short bits = 0; | ||
121 | |||
122 | unsigned value = instances[minor].pp_state; | ||
123 | if (! (value & 0x01)) bits |= BPP_PP_nStrobe; | ||
124 | if (! (value & 0x02)) bits |= BPP_PP_nAutoFd; | ||
125 | if (value & 0x04) bits |= BPP_PP_nInit; | ||
126 | if (! (value & 0x08)) bits |= BPP_PP_nSelectIn; | ||
127 | |||
128 | value = inb_p(base_addrs[minor]+1); | ||
129 | if (value & 0x08) bits |= BPP_GP_nFault; | ||
130 | if (value & 0x10) bits |= BPP_GP_Select; | ||
131 | if (value & 0x20) bits |= BPP_GP_PError; | ||
132 | if (value & 0x40) bits |= BPP_GP_nAck; | ||
133 | if (! (value & 0x80)) bits |= BPP_GP_Busy; | ||
134 | |||
135 | return bits; | ||
136 | } | ||
137 | |||
138 | #endif /* __i386__ */ | ||
139 | |||
140 | #if defined(__sparc__) | ||
141 | |||
142 | /* | ||
143 | * Register block | ||
144 | */ | ||
145 | /* DMA registers */ | ||
146 | #define BPP_CSR 0x00 | ||
147 | #define BPP_ADDR 0x04 | ||
148 | #define BPP_BCNT 0x08 | ||
149 | #define BPP_TST_CSR 0x0C | ||
150 | /* Parallel Port registers */ | ||
151 | #define BPP_HCR 0x10 | ||
152 | #define BPP_OCR 0x12 | ||
153 | #define BPP_DR 0x14 | ||
154 | #define BPP_TCR 0x15 | ||
155 | #define BPP_OR 0x16 | ||
156 | #define BPP_IR 0x17 | ||
157 | #define BPP_ICR 0x18 | ||
158 | #define BPP_SIZE 0x1A | ||
159 | |||
160 | /* BPP_CSR. Bits of type RW1 are cleared with writing '1'. */ | ||
161 | #define P_DEV_ID_MASK 0xf0000000 /* R */ | ||
162 | #define P_DEV_ID_ZEBRA 0x40000000 | ||
163 | #define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */ | ||
164 | #define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */ | ||
165 | #define P_A_LOADED 0x04000000 /* R */ | ||
166 | #define P_DMA_ON 0x02000000 /* R DMA is not disabled */ | ||
167 | #define P_EN_NEXT 0x01000000 /* RW */ | ||
168 | #define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */ | ||
169 | #define P_DIAG 0x00100000 /* RW Disables draining and resetting | ||
170 | of P-FIFO on loading of P_ADDR*/ | ||
171 | #define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */ | ||
172 | #define P_BURST_8 0x00000000 | ||
173 | #define P_BURST_4 0x00040000 | ||
174 | #define P_BURST_1 0x00080000 /* "No burst" write */ | ||
175 | #define P_TC 0x00004000 /* RW1 Term Count, can be cleared when | ||
176 | P_EN_NEXT=1 */ | ||
177 | #define P_EN_CNT 0x00002000 /* RW */ | ||
178 | #define P_EN_DMA 0x00000200 /* RW */ | ||
179 | #define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */ | ||
180 | #define P_RESET 0x00000080 /* RW */ | ||
181 | #define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */ | ||
182 | #define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */ | ||
183 | #define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */ | ||
184 | #define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */ | ||
185 | #define P_ERR_PEND 0x00000002 /* R */ | ||
186 | #define P_INT_PEND 0x00000001 /* R */ | ||
187 | |||
188 | /* BPP_HCR. Time is in increments of SBus clock. */ | ||
189 | #define P_HCR_TEST 0x8000 /* Allows buried counters to be read */ | ||
190 | #define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */ | ||
191 | #define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) */ | ||
192 | |||
193 | /* BPP_OCR. */ | ||
194 | #define P_OCR_MEM_CLR 0x8000 | ||
195 | #define P_OCR_DATA_SRC 0x4000 /* ) */ | ||
196 | #define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */ | ||
197 | #define P_OCR_BUSY_DSEL 0x1000 /* ) selects */ | ||
198 | #define P_OCR_ACK_DSEL 0x0800 /* ) */ | ||
199 | #define P_OCR_EN_DIAG 0x0400 | ||
200 | #define P_OCR_BUSY_OP 0x0200 /* Busy operation */ | ||
201 | #define P_OCR_ACK_OP 0x0100 /* Ack operation */ | ||
202 | #define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */ | ||
203 | #define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */ | ||
204 | #define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */ | ||
205 | #define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. */ | ||
206 | |||
207 | /* BPP_TCR */ | ||
208 | #define P_TCR_DIR 0x08 | ||
209 | #define P_TCR_BUSY 0x04 | ||
210 | #define P_TCR_ACK 0x02 | ||
211 | #define P_TCR_DS 0x01 /* Strobe */ | ||
212 | |||
213 | /* BPP_OR */ | ||
214 | #define P_OR_V3 0x20 /* ) */ | ||
215 | #define P_OR_V2 0x10 /* ) on Zebra only */ | ||
216 | #define P_OR_V1 0x08 /* ) */ | ||
217 | #define P_OR_INIT 0x04 | ||
218 | #define P_OR_AFXN 0x02 /* Auto Feed */ | ||
219 | #define P_OR_SLCT_IN 0x01 | ||
220 | |||
221 | /* BPP_IR */ | ||
222 | #define P_IR_PE 0x04 | ||
223 | #define P_IR_SLCT 0x02 | ||
224 | #define P_IR_ERR 0x01 | ||
225 | |||
226 | /* BPP_ICR */ | ||
227 | #define P_DS_IRQ 0x8000 /* RW1 */ | ||
228 | #define P_ACK_IRQ 0x4000 /* RW1 */ | ||
229 | #define P_BUSY_IRQ 0x2000 /* RW1 */ | ||
230 | #define P_PE_IRQ 0x1000 /* RW1 */ | ||
231 | #define P_SLCT_IRQ 0x0800 /* RW1 */ | ||
232 | #define P_ERR_IRQ 0x0400 /* RW1 */ | ||
233 | #define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */ | ||
234 | #define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */ | ||
235 | #define P_BUSY_IRP 0x0080 /* RW 1= rising edge */ | ||
236 | #define P_BUSY_IRQ_EN 0x0040 /* RW */ | ||
237 | #define P_PE_IRP 0x0020 /* RW 1= rising edge */ | ||
238 | #define P_PE_IRQ_EN 0x0010 /* RW */ | ||
239 | #define P_SLCT_IRP 0x0008 /* RW 1= rising edge */ | ||
240 | #define P_SLCT_IRQ_EN 0x0004 /* RW */ | ||
241 | #define P_ERR_IRP 0x0002 /* RW1 1= rising edge */ | ||
242 | #define P_ERR_IRQ_EN 0x0001 /* RW */ | ||
243 | |||
244 | static void __iomem *base_addrs[BPP_NO]; | ||
245 | |||
246 | #define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR) | ||
247 | #define bpp_inb_p(base) sbus_readb((base) + BPP_DR) | ||
248 | #define bpp_inb(base) sbus_readb((base) + BPP_DR) | ||
249 | |||
250 | static void set_pins(unsigned short pins, unsigned minor) | ||
251 | { | ||
252 | void __iomem *base = base_addrs[minor]; | ||
253 | unsigned char bits_tcr = 0, bits_or = 0; | ||
254 | |||
255 | if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR; | ||
256 | if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS; | ||
257 | |||
258 | if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN; | ||
259 | if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT; | ||
260 | if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN; | ||
261 | |||
262 | sbus_writeb(bits_or, base + BPP_OR); | ||
263 | sbus_writeb(bits_tcr, base + BPP_TCR); | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * i386 people read output pins from a software image. | ||
268 | * We may get them back from hardware. | ||
269 | * Again, inversion of pins must he buried here. | ||
270 | */ | ||
271 | static unsigned short get_pins(unsigned minor) | ||
272 | { | ||
273 | void __iomem *base = base_addrs[minor]; | ||
274 | unsigned short bits = 0; | ||
275 | unsigned value_tcr = sbus_readb(base + BPP_TCR); | ||
276 | unsigned value_ir = sbus_readb(base + BPP_IR); | ||
277 | unsigned value_or = sbus_readb(base + BPP_OR); | ||
278 | |||
279 | if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe; | ||
280 | if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd; | ||
281 | if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit; | ||
282 | if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn; | ||
283 | |||
284 | if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault; | ||
285 | if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select; | ||
286 | if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError; | ||
287 | if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck; | ||
288 | if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy; | ||
289 | |||
290 | return bits; | ||
291 | } | ||
292 | |||
293 | #endif /* __sparc__ */ | ||
294 | |||
295 | static void snooze(unsigned long snooze_time, unsigned minor) | ||
296 | { | ||
297 | schedule_timeout_uninterruptible(snooze_time + 1); | ||
298 | } | ||
299 | |||
300 | static int wait_for(unsigned short set, unsigned short clr, | ||
301 | unsigned long delay, unsigned minor) | ||
302 | { | ||
303 | unsigned short pins = get_pins(minor); | ||
304 | |||
305 | unsigned long extime = 0; | ||
306 | |||
307 | /* | ||
308 | * Try a real fast scan for the first jiffy, in case the device | ||
309 | * responds real good. The first while loop guesses an expire | ||
310 | * time accounting for possible wraparound of jiffies. | ||
311 | */ | ||
312 | while (time_after_eq(jiffies, extime)) extime = jiffies + 1; | ||
313 | while ( (time_before(jiffies, extime)) | ||
314 | && (((pins & set) != set) || ((pins & clr) != 0)) ) { | ||
315 | pins = get_pins(minor); | ||
316 | } | ||
317 | |||
318 | delay -= 1; | ||
319 | |||
320 | /* | ||
321 | * If my delay expired or the pins are still not where I want | ||
322 | * them, then resort to using the timer and greatly reduce my | ||
323 | * sample rate. If the peripheral is going to be slow, this will | ||
324 | * give the CPU up to some more worthy process. | ||
325 | */ | ||
326 | while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) { | ||
327 | |||
328 | snooze(1, minor); | ||
329 | pins = get_pins(minor); | ||
330 | delay -= 1; | ||
331 | } | ||
332 | |||
333 | if (delay == 0) return -1; | ||
334 | else return pins; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An | ||
339 | * errno means something broke, and I do not yet know how to fix it. | ||
340 | */ | ||
341 | static int negotiate(unsigned char mode, unsigned minor) | ||
342 | { | ||
343 | int rc; | ||
344 | unsigned short pins = get_pins(minor); | ||
345 | if (pins & BPP_PP_nSelectIn) return -EIO; | ||
346 | |||
347 | |||
348 | /* Event 0: Write the mode to the data lines */ | ||
349 | bpp_outb_p(mode, base_addrs[minor]); | ||
350 | |||
351 | snooze(TIME_PSetup, minor); | ||
352 | |||
353 | /* Event 1: Strobe the mode code into the peripheral */ | ||
354 | set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor); | ||
355 | |||
356 | /* Wait for Event 2: Peripheral responds as a 1284 device. */ | ||
357 | rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault, | ||
358 | BPP_GP_nAck, | ||
359 | TIME_PResponse, | ||
360 | minor); | ||
361 | |||
362 | if (rc == -1) return -ETIMEDOUT; | ||
363 | |||
364 | /* Event 3: latch extensibility request */ | ||
365 | set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor); | ||
366 | |||
367 | /* ... quick nap while peripheral ponders the byte i'm sending...*/ | ||
368 | snooze(1, minor); | ||
369 | |||
370 | /* Event 4: restore strobe, to ACK peripheral's response. */ | ||
371 | set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); | ||
372 | |||
373 | /* Wait for Event 6: Peripheral latches response bits */ | ||
374 | rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor); | ||
375 | if (rc == -1) return -EIO; | ||
376 | |||
377 | /* A 1284 device cannot refuse nibble mode */ | ||
378 | if (mode == DEFAULT_NIBBLE) return 0; | ||
379 | |||
380 | if (pins & BPP_GP_Select) return 0; | ||
381 | |||
382 | return -EPROTONOSUPPORT; | ||
383 | } | ||
384 | |||
385 | static int terminate(unsigned minor) | ||
386 | { | ||
387 | int rc; | ||
388 | |||
389 | /* Event 22: Request termination of 1284 mode */ | ||
390 | set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); | ||
391 | |||
392 | /* Wait for Events 23 and 24: ACK termination request. */ | ||
393 | rc = wait_for(BPP_GP_Busy|BPP_GP_nFault, | ||
394 | BPP_GP_nAck, | ||
395 | TIME_PSetup+TIME_PResponse, | ||
396 | minor); | ||
397 | |||
398 | instances[minor].direction = 0; | ||
399 | instances[minor].mode = COMPATIBILITY; | ||
400 | |||
401 | if (rc == -1) { | ||
402 | return -EIO; | ||
403 | } | ||
404 | |||
405 | /* Event 25: Handshake by lowering nAutoFd */ | ||
406 | set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor); | ||
407 | |||
408 | /* Event 26: Peripheral wiggles lines... */ | ||
409 | |||
410 | /* Event 27: Peripheral sets nAck HIGH to ack handshake */ | ||
411 | rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); | ||
412 | if (rc == -1) { | ||
413 | set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); | ||
414 | return -EIO; | ||
415 | } | ||
416 | |||
417 | /* Event 28: Finish phase by raising nAutoFd */ | ||
418 | set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static DEFINE_SPINLOCK(bpp_open_lock); | ||
424 | |||
425 | /* | ||
426 | * Allow only one process to open the device at a time. | ||
427 | */ | ||
428 | static int bpp_open(struct inode *inode, struct file *f) | ||
429 | { | ||
430 | unsigned minor = iminor(inode); | ||
431 | int ret; | ||
432 | |||
433 | lock_kernel(); | ||
434 | spin_lock(&bpp_open_lock); | ||
435 | ret = 0; | ||
436 | if (minor >= BPP_NO) { | ||
437 | ret = -ENODEV; | ||
438 | } else { | ||
439 | if (! instances[minor].present) { | ||
440 | ret = -ENODEV; | ||
441 | } else { | ||
442 | if (instances[minor].opened) | ||
443 | ret = -EBUSY; | ||
444 | else | ||
445 | instances[minor].opened = 1; | ||
446 | } | ||
447 | } | ||
448 | spin_unlock(&bpp_open_lock); | ||
449 | unlock_kernel(); | ||
450 | |||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * When the process closes the device, this method is called to clean | ||
456 | * up and reset the hardware. Always leave the device in compatibility | ||
457 | * mode as this is a reasonable place to clean up from messes made by | ||
458 | * ioctls, or other mayhem. | ||
459 | */ | ||
460 | static int bpp_release(struct inode *inode, struct file *f) | ||
461 | { | ||
462 | unsigned minor = iminor(inode); | ||
463 | |||
464 | spin_lock(&bpp_open_lock); | ||
465 | instances[minor].opened = 0; | ||
466 | |||
467 | if (instances[minor].mode != COMPATIBILITY) | ||
468 | terminate(minor); | ||
469 | |||
470 | spin_unlock(&bpp_open_lock); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static long read_nibble(unsigned minor, char __user *c, unsigned long cnt) | ||
476 | { | ||
477 | unsigned long remaining = cnt; | ||
478 | long rc; | ||
479 | |||
480 | while (remaining > 0) { | ||
481 | unsigned char byte = 0; | ||
482 | int pins; | ||
483 | |||
484 | /* Event 7: request nibble */ | ||
485 | set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); | ||
486 | |||
487 | /* Wait for event 9: Peripher strobes first nibble */ | ||
488 | pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); | ||
489 | if (pins == -1) return -ETIMEDOUT; | ||
490 | |||
491 | /* Event 10: I handshake nibble */ | ||
492 | set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); | ||
493 | if (pins & BPP_GP_nFault) byte |= 0x01; | ||
494 | if (pins & BPP_GP_Select) byte |= 0x02; | ||
495 | if (pins & BPP_GP_PError) byte |= 0x04; | ||
496 | if (pins & BPP_GP_Busy) byte |= 0x08; | ||
497 | |||
498 | /* Wait for event 11: Peripheral handshakes nibble */ | ||
499 | rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); | ||
500 | |||
501 | /* Event 7: request nibble */ | ||
502 | set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); | ||
503 | |||
504 | /* Wait for event 9: Peripher strobes first nibble */ | ||
505 | pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor); | ||
506 | if (rc == -1) return -ETIMEDOUT; | ||
507 | |||
508 | /* Event 10: I handshake nibble */ | ||
509 | set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); | ||
510 | if (pins & BPP_GP_nFault) byte |= 0x10; | ||
511 | if (pins & BPP_GP_Select) byte |= 0x20; | ||
512 | if (pins & BPP_GP_PError) byte |= 0x40; | ||
513 | if (pins & BPP_GP_Busy) byte |= 0x80; | ||
514 | |||
515 | if (put_user(byte, c)) | ||
516 | return -EFAULT; | ||
517 | c += 1; | ||
518 | remaining -= 1; | ||
519 | |||
520 | /* Wait for event 11: Peripheral handshakes nibble */ | ||
521 | rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); | ||
522 | if (rc == -1) return -EIO; | ||
523 | } | ||
524 | |||
525 | return cnt - remaining; | ||
526 | } | ||
527 | |||
528 | static long read_ecp(unsigned minor, char __user *c, unsigned long cnt) | ||
529 | { | ||
530 | unsigned long remaining; | ||
531 | long rc; | ||
532 | |||
533 | /* Turn ECP mode from forward to reverse if needed. */ | ||
534 | if (! instances[minor].direction) { | ||
535 | unsigned short pins = get_pins(minor); | ||
536 | |||
537 | /* Event 38: Turn the bus around */ | ||
538 | instances[minor].direction = 0x20; | ||
539 | pins &= ~BPP_PP_nAutoFd; | ||
540 | set_pins(pins, minor); | ||
541 | |||
542 | /* Event 39: Set pins for reverse mode. */ | ||
543 | snooze(TIME_PSetup, minor); | ||
544 | set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); | ||
545 | |||
546 | /* Wait for event 40: Peripheral ready to be strobed */ | ||
547 | rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor); | ||
548 | if (rc == -1) return -ETIMEDOUT; | ||
549 | } | ||
550 | |||
551 | remaining = cnt; | ||
552 | |||
553 | while (remaining > 0) { | ||
554 | |||
555 | /* If there is a run length for a repeated byte, repeat */ | ||
556 | /* that byte a few times. */ | ||
557 | if (instances[minor].run_length && !instances[minor].run_flag) { | ||
558 | |||
559 | char buffer[128]; | ||
560 | unsigned idx; | ||
561 | unsigned repeat = remaining < instances[minor].run_length | ||
562 | ? remaining | ||
563 | : instances[minor].run_length; | ||
564 | |||
565 | for (idx = 0 ; idx < repeat ; idx += 1) | ||
566 | buffer[idx] = instances[minor].repeat_byte; | ||
567 | |||
568 | if (copy_to_user(c, buffer, repeat)) | ||
569 | return -EFAULT; | ||
570 | remaining -= repeat; | ||
571 | c += repeat; | ||
572 | instances[minor].run_length -= repeat; | ||
573 | } | ||
574 | |||
575 | if (remaining == 0) break; | ||
576 | |||
577 | |||
578 | /* Wait for Event 43: Data active on the bus. */ | ||
579 | rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); | ||
580 | if (rc == -1) break; | ||
581 | |||
582 | if (rc & BPP_GP_Busy) { | ||
583 | /* OK, this is data. read it in. */ | ||
584 | unsigned char byte = bpp_inb(base_addrs[minor]); | ||
585 | if (put_user(byte, c)) | ||
586 | return -EFAULT; | ||
587 | c += 1; | ||
588 | remaining -= 1; | ||
589 | |||
590 | if (instances[minor].run_flag) { | ||
591 | instances[minor].repeat_byte = byte; | ||
592 | instances[minor].run_flag = 0; | ||
593 | } | ||
594 | |||
595 | } else { | ||
596 | unsigned char byte = bpp_inb(base_addrs[minor]); | ||
597 | if (byte & 0x80) { | ||
598 | printk("bpp%d: " | ||
599 | "Ignoring ECP channel %u from device.\n", | ||
600 | minor, byte & 0x7f); | ||
601 | } else { | ||
602 | instances[minor].run_length = byte; | ||
603 | instances[minor].run_flag = 1; | ||
604 | } | ||
605 | } | ||
606 | |||
607 | /* Event 44: I got it. */ | ||
608 | set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor); | ||
609 | |||
610 | /* Wait for event 45: peripheral handshake */ | ||
611 | rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); | ||
612 | if (rc == -1) return -ETIMEDOUT; | ||
613 | |||
614 | /* Event 46: Finish handshake */ | ||
615 | set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); | ||
616 | |||
617 | } | ||
618 | |||
619 | |||
620 | return cnt - remaining; | ||
621 | } | ||
622 | |||
623 | static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos) | ||
624 | { | ||
625 | long rc; | ||
626 | unsigned minor = iminor(f->f_path.dentry->d_inode); | ||
627 | if (minor >= BPP_NO) return -ENODEV; | ||
628 | if (!instances[minor].present) return -ENODEV; | ||
629 | |||
630 | switch (instances[minor].mode) { | ||
631 | |||
632 | default: | ||
633 | if (instances[minor].mode != COMPATIBILITY) | ||
634 | terminate(minor); | ||
635 | |||
636 | if (instances[minor].enhanced) { | ||
637 | /* For now, do all reads with ECP-RLE mode */ | ||
638 | unsigned short pins; | ||
639 | |||
640 | rc = negotiate(DEFAULT_ECP, minor); | ||
641 | if (rc < 0) break; | ||
642 | |||
643 | instances[minor].mode = ECP_RLE; | ||
644 | |||
645 | /* Event 30: set nAutoFd low to setup for ECP mode */ | ||
646 | pins = get_pins(minor); | ||
647 | pins &= ~BPP_PP_nAutoFd; | ||
648 | set_pins(pins, minor); | ||
649 | |||
650 | /* Wait for Event 31: peripheral ready */ | ||
651 | rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); | ||
652 | if (rc == -1) return -ETIMEDOUT; | ||
653 | |||
654 | rc = read_ecp(minor, c, cnt); | ||
655 | |||
656 | } else { | ||
657 | rc = negotiate(DEFAULT_NIBBLE, minor); | ||
658 | if (rc < 0) break; | ||
659 | |||
660 | instances[minor].mode = NIBBLE; | ||
661 | |||
662 | rc = read_nibble(minor, c, cnt); | ||
663 | } | ||
664 | break; | ||
665 | |||
666 | case NIBBLE: | ||
667 | rc = read_nibble(minor, c, cnt); | ||
668 | break; | ||
669 | |||
670 | case ECP: | ||
671 | case ECP_RLE: | ||
672 | rc = read_ecp(minor, c, cnt); | ||
673 | break; | ||
674 | |||
675 | } | ||
676 | |||
677 | |||
678 | return rc; | ||
679 | } | ||
680 | |||
681 | /* | ||
682 | * Compatibility mode handshaking is a matter of writing data, | ||
683 | * strobing it, and waiting for the printer to stop being busy. | ||
684 | */ | ||
685 | static long write_compat(unsigned minor, const char __user *c, unsigned long cnt) | ||
686 | { | ||
687 | long rc; | ||
688 | unsigned short pins = get_pins(minor); | ||
689 | |||
690 | unsigned long remaining = cnt; | ||
691 | |||
692 | |||
693 | while (remaining > 0) { | ||
694 | unsigned char byte; | ||
695 | |||
696 | if (get_user(byte, c)) | ||
697 | return -EFAULT; | ||
698 | c += 1; | ||
699 | |||
700 | rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); | ||
701 | if (rc == -1) return -ETIMEDOUT; | ||
702 | |||
703 | bpp_outb_p(byte, base_addrs[minor]); | ||
704 | remaining -= 1; | ||
705 | /* snooze(1, minor); */ | ||
706 | |||
707 | pins &= ~BPP_PP_nStrobe; | ||
708 | set_pins(pins, minor); | ||
709 | |||
710 | rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); | ||
711 | |||
712 | pins |= BPP_PP_nStrobe; | ||
713 | set_pins(pins, minor); | ||
714 | } | ||
715 | |||
716 | return cnt - remaining; | ||
717 | } | ||
718 | |||
719 | /* | ||
720 | * Write data using ECP mode. Watch out that the port may be set up | ||
721 | * for reading. If so, turn the port around. | ||
722 | */ | ||
723 | static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt) | ||
724 | { | ||
725 | unsigned short pins = get_pins(minor); | ||
726 | unsigned long remaining = cnt; | ||
727 | |||
728 | if (instances[minor].direction) { | ||
729 | int rc; | ||
730 | |||
731 | /* Event 47 Request bus be turned around */ | ||
732 | pins |= BPP_PP_nInit; | ||
733 | set_pins(pins, minor); | ||
734 | |||
735 | /* Wait for Event 49: Peripheral relinquished bus */ | ||
736 | rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); | ||
737 | |||
738 | pins |= BPP_PP_nAutoFd; | ||
739 | instances[minor].direction = 0; | ||
740 | set_pins(pins, minor); | ||
741 | } | ||
742 | |||
743 | while (remaining > 0) { | ||
744 | unsigned char byte; | ||
745 | int rc; | ||
746 | |||
747 | if (get_user(byte, c)) | ||
748 | return -EFAULT; | ||
749 | |||
750 | rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor); | ||
751 | if (rc == -1) return -ETIMEDOUT; | ||
752 | |||
753 | c += 1; | ||
754 | |||
755 | bpp_outb_p(byte, base_addrs[minor]); | ||
756 | |||
757 | pins &= ~BPP_PP_nStrobe; | ||
758 | set_pins(pins, minor); | ||
759 | |||
760 | pins |= BPP_PP_nStrobe; | ||
761 | rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); | ||
762 | if (rc == -1) return -EIO; | ||
763 | |||
764 | set_pins(pins, minor); | ||
765 | } | ||
766 | |||
767 | return cnt - remaining; | ||
768 | } | ||
769 | |||
770 | /* | ||
771 | * Write to the peripheral. Be sensitive of the current mode. If I'm | ||
772 | * in a mode that can be turned around (ECP) then just do | ||
773 | * that. Otherwise, terminate and do my writing in compat mode. This | ||
774 | * is the safest course as any device can handle it. | ||
775 | */ | ||
776 | static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos) | ||
777 | { | ||
778 | long errno = 0; | ||
779 | unsigned minor = iminor(f->f_path.dentry->d_inode); | ||
780 | if (minor >= BPP_NO) return -ENODEV; | ||
781 | if (!instances[minor].present) return -ENODEV; | ||
782 | |||
783 | switch (instances[minor].mode) { | ||
784 | |||
785 | case ECP: | ||
786 | case ECP_RLE: | ||
787 | errno = write_ecp(minor, c, cnt); | ||
788 | break; | ||
789 | case COMPATIBILITY: | ||
790 | errno = write_compat(minor, c, cnt); | ||
791 | break; | ||
792 | default: | ||
793 | terminate(minor); | ||
794 | errno = write_compat(minor, c, cnt); | ||
795 | } | ||
796 | |||
797 | return errno; | ||
798 | } | ||
799 | |||
800 | static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd, | ||
801 | unsigned long arg) | ||
802 | { | ||
803 | int errno = 0; | ||
804 | |||
805 | unsigned minor = iminor(inode); | ||
806 | if (minor >= BPP_NO) return -ENODEV; | ||
807 | if (!instances[minor].present) return -ENODEV; | ||
808 | |||
809 | |||
810 | switch (cmd) { | ||
811 | |||
812 | case BPP_PUT_PINS: | ||
813 | set_pins(arg, minor); | ||
814 | break; | ||
815 | |||
816 | case BPP_GET_PINS: | ||
817 | errno = get_pins(minor); | ||
818 | break; | ||
819 | |||
820 | case BPP_PUT_DATA: | ||
821 | bpp_outb_p(arg, base_addrs[minor]); | ||
822 | break; | ||
823 | |||
824 | case BPP_GET_DATA: | ||
825 | errno = bpp_inb_p(base_addrs[minor]); | ||
826 | break; | ||
827 | |||
828 | case BPP_SET_INPUT: | ||
829 | if (arg) | ||
830 | if (instances[minor].enhanced) { | ||
831 | unsigned short bits = get_pins(minor); | ||
832 | instances[minor].direction = 0x20; | ||
833 | set_pins(bits, minor); | ||
834 | } else { | ||
835 | errno = -ENOTTY; | ||
836 | } | ||
837 | else { | ||
838 | unsigned short bits = get_pins(minor); | ||
839 | instances[minor].direction = 0x00; | ||
840 | set_pins(bits, minor); | ||
841 | } | ||
842 | break; | ||
843 | |||
844 | default: | ||
845 | errno = -EINVAL; | ||
846 | } | ||
847 | |||
848 | return errno; | ||
849 | } | ||
850 | |||
851 | static const struct file_operations bpp_fops = { | ||
852 | .owner = THIS_MODULE, | ||
853 | .read = bpp_read, | ||
854 | .write = bpp_write, | ||
855 | .ioctl = bpp_ioctl, | ||
856 | .open = bpp_open, | ||
857 | .release = bpp_release, | ||
858 | }; | ||
859 | |||
860 | #if defined(__i386__) | ||
861 | |||
862 | #define collectLptPorts() {} | ||
863 | |||
864 | static void probeLptPort(unsigned idx) | ||
865 | { | ||
866 | unsigned int testvalue; | ||
867 | const unsigned short lpAddr = base_addrs[idx]; | ||
868 | |||
869 | instances[idx].present = 0; | ||
870 | instances[idx].enhanced = 0; | ||
871 | instances[idx].direction = 0; | ||
872 | instances[idx].mode = COMPATIBILITY; | ||
873 | instances[idx].run_length = 0; | ||
874 | instances[idx].run_flag = 0; | ||
875 | if (!request_region(lpAddr,3, bpp_dev_name)) return; | ||
876 | |||
877 | /* | ||
878 | * First, make sure the instance exists. Do this by writing to | ||
879 | * the data latch and reading the value back. If the port *is* | ||
880 | * present, test to see if it supports extended-mode | ||
881 | * operation. This will be required for IEEE1284 reverse | ||
882 | * transfers. | ||
883 | */ | ||
884 | |||
885 | outb_p(BPP_PROBE_CODE, lpAddr); | ||
886 | for (testvalue=0; testvalue<BPP_DELAY; testvalue++) | ||
887 | ; | ||
888 | testvalue = inb_p(lpAddr); | ||
889 | if (testvalue == BPP_PROBE_CODE) { | ||
890 | unsigned save; | ||
891 | instances[idx].present = 1; | ||
892 | |||
893 | save = inb_p(lpAddr+2); | ||
894 | for (testvalue=0; testvalue<BPP_DELAY; testvalue++) | ||
895 | ; | ||
896 | outb_p(save|0x20, lpAddr+2); | ||
897 | for (testvalue=0; testvalue<BPP_DELAY; testvalue++) | ||
898 | ; | ||
899 | outb_p(~BPP_PROBE_CODE, lpAddr); | ||
900 | for (testvalue=0; testvalue<BPP_DELAY; testvalue++) | ||
901 | ; | ||
902 | testvalue = inb_p(lpAddr); | ||
903 | if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE)) | ||
904 | instances[idx].enhanced = 0; | ||
905 | else | ||
906 | instances[idx].enhanced = 1; | ||
907 | outb_p(save, lpAddr+2); | ||
908 | } | ||
909 | else { | ||
910 | release_region(lpAddr,3); | ||
911 | } | ||
912 | /* | ||
913 | * Leave the port in compat idle mode. | ||
914 | */ | ||
915 | set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); | ||
916 | |||
917 | printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx], | ||
918 | instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE"); | ||
919 | } | ||
920 | |||
921 | static inline void freeLptPort(int idx) | ||
922 | { | ||
923 | release_region(base_addrs[idx], 3); | ||
924 | } | ||
925 | |||
926 | #endif | ||
927 | |||
928 | #if defined(__sparc__) | ||
929 | |||
930 | static void __iomem *map_bpp(struct sbus_dev *dev, int idx) | ||
931 | { | ||
932 | return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp"); | ||
933 | } | ||
934 | |||
935 | static int collectLptPorts(void) | ||
936 | { | ||
937 | struct sbus_bus *bus; | ||
938 | struct sbus_dev *dev; | ||
939 | int count; | ||
940 | |||
941 | count = 0; | ||
942 | for_all_sbusdev(dev, bus) { | ||
943 | if (strcmp(dev->prom_name, "SUNW,bpp") == 0) { | ||
944 | if (count >= BPP_NO) { | ||
945 | printk(KERN_NOTICE | ||
946 | "bpp: More than %d bpp ports," | ||
947 | " rest is ignored\n", BPP_NO); | ||
948 | return count; | ||
949 | } | ||
950 | base_addrs[count] = map_bpp(dev, count); | ||
951 | count++; | ||
952 | } | ||
953 | } | ||
954 | return count; | ||
955 | } | ||
956 | |||
957 | static void probeLptPort(unsigned idx) | ||
958 | { | ||
959 | void __iomem *rp = base_addrs[idx]; | ||
960 | __u32 csr; | ||
961 | char *brand; | ||
962 | |||
963 | instances[idx].present = 0; | ||
964 | instances[idx].enhanced = 0; | ||
965 | instances[idx].direction = 0; | ||
966 | instances[idx].mode = COMPATIBILITY; | ||
967 | instances[idx].run_length = 0; | ||
968 | instances[idx].run_flag = 0; | ||
969 | |||
970 | if (!rp) return; | ||
971 | |||
972 | instances[idx].present = 1; | ||
973 | instances[idx].enhanced = 1; /* Sure */ | ||
974 | |||
975 | csr = sbus_readl(rp + BPP_CSR); | ||
976 | if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { | ||
977 | udelay(20); | ||
978 | csr = sbus_readl(rp + BPP_CSR); | ||
979 | if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { | ||
980 | printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr); | ||
981 | } | ||
982 | } | ||
983 | printk("bpp%d: reset with 0x%08x ..", idx, csr); | ||
984 | sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR); | ||
985 | udelay(500); | ||
986 | sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR); | ||
987 | csr = sbus_readl(rp + BPP_CSR); | ||
988 | printk(" done with csr=0x%08x ocr=0x%04x\n", | ||
989 | csr, sbus_readw(rp + BPP_OCR)); | ||
990 | |||
991 | switch (csr & P_DEV_ID_MASK) { | ||
992 | case P_DEV_ID_ZEBRA: | ||
993 | brand = "Zebra"; | ||
994 | break; | ||
995 | case P_DEV_ID_L64854: | ||
996 | brand = "DMA2"; | ||
997 | break; | ||
998 | default: | ||
999 | brand = "Unknown"; | ||
1000 | } | ||
1001 | printk("bpp%d: %s at %p\n", idx, brand, rp); | ||
1002 | |||
1003 | /* | ||
1004 | * Leave the port in compat idle mode. | ||
1005 | */ | ||
1006 | set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); | ||
1007 | |||
1008 | return; | ||
1009 | } | ||
1010 | |||
1011 | static inline void freeLptPort(int idx) | ||
1012 | { | ||
1013 | sbus_iounmap(base_addrs[idx], BPP_SIZE); | ||
1014 | } | ||
1015 | |||
1016 | #endif | ||
1017 | |||
1018 | static int __init bpp_init(void) | ||
1019 | { | ||
1020 | int rc; | ||
1021 | unsigned idx; | ||
1022 | |||
1023 | rc = collectLptPorts(); | ||
1024 | if (rc == 0) | ||
1025 | return -ENODEV; | ||
1026 | |||
1027 | rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops); | ||
1028 | if (rc < 0) | ||
1029 | return rc; | ||
1030 | |||
1031 | for (idx = 0; idx < BPP_NO; idx++) { | ||
1032 | instances[idx].opened = 0; | ||
1033 | probeLptPort(idx); | ||
1034 | } | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | |||
1039 | static void __exit bpp_cleanup(void) | ||
1040 | { | ||
1041 | unsigned idx; | ||
1042 | |||
1043 | unregister_chrdev(BPP_MAJOR, bpp_dev_name); | ||
1044 | |||
1045 | for (idx = 0; idx < BPP_NO; idx++) { | ||
1046 | if (instances[idx].present) | ||
1047 | freeLptPort(idx); | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1051 | module_init(bpp_init); | ||
1052 | module_exit(bpp_cleanup); | ||
1053 | |||
1054 | MODULE_LICENSE("GPL"); | ||
1055 | |||