]>
git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/block/paride/pt.c
2 pt.c (c) 1998 Grant R. Guenther <grant@torque.net>
3 Under the terms of the GNU General Public License.
5 This is the high-level driver for parallel port ATAPI tape
6 drives based on chips supported by the paride module.
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.
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.
20 The rewinding devices are named /dev/pt0, /dev/pt1, ...
21 while the non-rewinding devices are /dev/npt0, /dev/npt1, etc.
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:
27 drive0 These four arguments can be arrays of
28 drive1 1-6 integers as follows:
30 drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
34 <prt> is the base of the parallel port address for
35 the corresponding drive. (required)
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)
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.
48 <mod> this can be -1 to choose the best mode, or one
49 of the mode numbers supported by the adapter.
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
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)
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
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).
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
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:
89 In addition, you can use the parameter pt.disable to disable
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.
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,
103 1.04 GRG 1998.09.24 Repair minor coding error, added jumbo support
107 #define PT_VERSION "1.04"
112 /* Here are things one can override from the insmod command.
113 Most are autoprobed by paride unless set here. Verbose is on
118 static int verbose
= 0;
119 static int major
= PT_MAJOR
;
120 static char *name
= PT_NAME
;
121 static int disable
= 0;
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 };
128 static int (*drives
[4])[6] = {&drive0
, &drive1
, &drive2
, &drive3
};
137 #define DU (*drives[unit])
139 /* end of parameters */
141 #include <linux/module.h>
142 #include <linux/init.h>
143 #include <linux/fs.h>
144 #include <linux/delay.h>
145 #include <linux/slab.h>
146 #include <linux/mtio.h>
147 #include <linux/device.h>
148 #include <linux/sched.h> /* current, TASK_*, schedule_timeout() */
149 #include <linux/smp_lock.h>
151 #include <asm/uaccess.h>
153 module_param(verbose
, bool, 0);
154 module_param(major
, int, 0);
155 module_param(name
, charp
, 0);
156 module_param_array(drive0
, int, NULL
, 0);
157 module_param_array(drive1
, int, NULL
, 0);
158 module_param_array(drive2
, int, NULL
, 0);
159 module_param_array(drive3
, int, NULL
, 0);
163 #define PT_MAX_RETRIES 5
164 #define PT_TMO 3000 /* interrupt timeout in jiffies */
165 #define PT_SPIN_DEL 50 /* spin delay in micro-seconds */
166 #define PT_RESET_TMO 30 /* 30 seconds */
167 #define PT_READY_TMO 60 /* 60 seconds */
168 #define PT_REWIND_TMO 1200 /* 20 minutes */
170 #define PT_SPIN ((1000000/(HZ*PT_SPIN_DEL))*PT_TMO)
172 #define STAT_ERR 0x00001
173 #define STAT_INDEX 0x00002
174 #define STAT_ECC 0x00004
175 #define STAT_DRQ 0x00008
176 #define STAT_SEEK 0x00010
177 #define STAT_WRERR 0x00020
178 #define STAT_READY 0x00040
179 #define STAT_BUSY 0x00080
180 #define STAT_SENSE 0x1f000
182 #define ATAPI_TEST_READY 0x00
183 #define ATAPI_REWIND 0x01
184 #define ATAPI_REQ_SENSE 0x03
185 #define ATAPI_READ_6 0x08
186 #define ATAPI_WRITE_6 0x0a
187 #define ATAPI_WFM 0x10
188 #define ATAPI_IDENTIFY 0x12
189 #define ATAPI_MODE_SENSE 0x1a
190 #define ATAPI_LOG_SENSE 0x4d
192 static int pt_open(struct inode
*inode
, struct file
*file
);
193 static long pt_ioctl(struct file
*file
, 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);
201 /* bits in tape->flags */
204 #define PT_WRITE_OK 2
207 #define PT_READING 16
211 #define PT_BUFSIZE 16384
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 ? */
224 char name
[PT_NAMELEN
]; /* pf0, pf1, ... */
227 static int pt_identify(struct pt_unit
*tape
);
229 static struct pt_unit pt
[PT_UNITS
];
231 static char pt_scratch
[512]; /* scratch block buffer */
233 /* kernel glue structures */
235 static const struct file_operations pt_fops
= {
236 .owner
= THIS_MODULE
,
239 .unlocked_ioctl
= pt_ioctl
,
241 .release
= pt_release
,
242 .llseek
= noop_llseek
,
245 /* sysfs class support */
246 static struct class *pt_class
;
248 static inline int status_reg(struct pi_adapter
*pi
)
250 return pi_read_regr(pi
, 1, 6);
253 static inline int read_reg(struct pi_adapter
*pi
, int reg
)
255 return pi_read_regr(pi
, 0, reg
);
258 static inline void write_reg(struct pi_adapter
*pi
, int reg
, int val
)
260 pi_write_regr(pi
, 0, reg
, val
);
263 static inline u8
DRIVE(struct pt_unit
*tape
)
265 return 0xa0+0x10*tape
->drive
;
268 static int pt_wait(struct pt_unit
*tape
, int go
, int stop
, char *fun
, char *msg
)
271 struct pi_adapter
*pi
= tape
->pi
;
274 while ((((r
= status_reg(pi
)) & go
) || (stop
&& (!(r
& stop
))))
278 if ((r
& (STAT_ERR
& stop
)) || (j
> PT_SPIN
)) {
285 printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
286 " loop=%d phase=%d\n",
287 tape
->name
, fun
, msg
, r
, s
, e
, j
, p
);
293 static int pt_command(struct pt_unit
*tape
, char *cmd
, int dlen
, char *fun
)
295 struct pi_adapter
*pi
= tape
->pi
;
298 write_reg(pi
, 6, DRIVE(tape
));
300 if (pt_wait(tape
, STAT_BUSY
| STAT_DRQ
, 0, fun
, "before command")) {
305 write_reg(pi
, 4, dlen
% 256);
306 write_reg(pi
, 5, dlen
/ 256);
307 write_reg(pi
, 7, 0xa0); /* ATAPI packet command */
309 if (pt_wait(tape
, STAT_BUSY
, STAT_DRQ
, fun
, "command DRQ")) {
314 if (read_reg(pi
, 2) != 1) {
315 printk("%s: %s: command phase error\n", tape
->name
, fun
);
320 pi_write_block(pi
, cmd
, 12);
325 static int pt_completion(struct pt_unit
*tape
, char *buf
, char *fun
)
327 struct pi_adapter
*pi
= tape
->pi
;
330 r
= pt_wait(tape
, STAT_BUSY
, STAT_DRQ
| STAT_READY
| STAT_ERR
,
333 if (read_reg(pi
, 7) & STAT_DRQ
) {
334 n
= (((read_reg(pi
, 4) + 256 * read_reg(pi
, 5)) +
336 p
= read_reg(pi
, 2) & 3;
338 pi_write_block(pi
, buf
, n
);
340 pi_read_block(pi
, buf
, n
);
343 s
= pt_wait(tape
, STAT_BUSY
, STAT_READY
| STAT_ERR
, fun
, "data done");
350 static void pt_req_sense(struct pt_unit
*tape
, int quiet
)
352 char rs_cmd
[12] = { ATAPI_REQ_SENSE
, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
356 r
= pt_command(tape
, rs_cmd
, 16, "Request sense");
359 pt_completion(tape
, buf
, "Request sense");
361 tape
->last_sense
= -1;
364 printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
365 tape
->name
, buf
[2] & 0xf, buf
[12], buf
[13]);
366 tape
->last_sense
= (buf
[2] & 0xf) | ((buf
[12] & 0xff) << 8)
367 | ((buf
[13] & 0xff) << 16);
371 static int pt_atapi(struct pt_unit
*tape
, char *cmd
, int dlen
, char *buf
, char *fun
)
375 r
= pt_command(tape
, cmd
, dlen
, fun
);
378 r
= pt_completion(tape
, buf
, fun
);
380 pt_req_sense(tape
, !fun
);
385 static void pt_sleep(int cs
)
387 schedule_timeout_interruptible(cs
);
390 static int pt_poll_dsc(struct pt_unit
*tape
, int pause
, int tmo
, char *msg
)
392 struct pi_adapter
*pi
= tape
->pi
;
402 write_reg(pi
, 6, DRIVE(tape
));
406 if (s
& (STAT_ERR
| STAT_SEEK
))
409 if ((k
>= tmo
) || (s
& STAT_ERR
)) {
411 printk("%s: %s DSC timeout\n", tape
->name
, msg
);
413 printk("%s: %s stat=0x%x err=0x%x\n", tape
->name
, msg
, s
,
415 pt_req_sense(tape
, 0);
421 static void pt_media_access_cmd(struct pt_unit
*tape
, int tmo
, char *cmd
, char *fun
)
423 if (pt_command(tape
, cmd
, 0, fun
)) {
424 pt_req_sense(tape
, 0);
427 pi_disconnect(tape
->pi
);
428 pt_poll_dsc(tape
, HZ
, tmo
, fun
);
431 static void pt_rewind(struct pt_unit
*tape
)
433 char rw_cmd
[12] = { ATAPI_REWIND
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
435 pt_media_access_cmd(tape
, PT_REWIND_TMO
, rw_cmd
, "rewind");
438 static void pt_write_fm(struct pt_unit
*tape
)
440 char wm_cmd
[12] = { ATAPI_WFM
, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
442 pt_media_access_cmd(tape
, PT_TMO
, wm_cmd
, "write filemark");
445 #define DBMSG(msg) ((verbose>1)?(msg):NULL)
447 static int pt_reset(struct pt_unit
*tape
)
449 struct pi_adapter
*pi
= tape
->pi
;
451 int expect
[5] = { 1, 1, 1, 0x14, 0xeb };
454 write_reg(pi
, 6, DRIVE(tape
));
457 pt_sleep(20 * HZ
/ 1000);
460 while ((k
++ < PT_RESET_TMO
) && (status_reg(pi
) & STAT_BUSY
))
464 for (i
= 0; i
< 5; i
++)
465 flg
&= (read_reg(pi
, i
+ 1) == expect
[i
]);
468 printk("%s: Reset (%d) signature = ", tape
->name
, k
);
469 for (i
= 0; i
< 5; i
++)
470 printk("%3x", read_reg(pi
, i
+ 1));
472 printk(" (incorrect)");
480 static int pt_ready_wait(struct pt_unit
*tape
, int tmo
)
482 char tr_cmd
[12] = { ATAPI_TEST_READY
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
487 tape
->last_sense
= 0;
488 pt_atapi(tape
, tr_cmd
, 0, NULL
, DBMSG("test unit ready"));
489 p
= tape
->last_sense
;
492 if (!(((p
& 0xffff) == 0x0402) || ((p
& 0xff) == 6)))
497 return 0x000020; /* timeout */
500 static void xs(char *buf
, char *targ
, int offs
, int len
)
506 for (k
= 0; k
< len
; k
++)
507 if ((buf
[k
+ offs
] != 0x20) || (buf
[k
+ offs
] != l
))
508 l
= targ
[j
++] = buf
[k
+ offs
];
514 static int xn(char *buf
, int offs
, int size
)
519 for (k
= 0; k
< size
; k
++)
520 v
= v
* 256 + (buf
[k
+ offs
] & 0xff);
524 static int pt_identify(struct pt_unit
*tape
)
527 char *ms
[2] = { "master", "slave" };
529 char id_cmd
[12] = { ATAPI_IDENTIFY
, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
531 { ATAPI_MODE_SENSE
, 0, 0x2a, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
533 { ATAPI_LOG_SENSE
, 0, 0x71, 0, 0, 0, 0, 0, 36, 0, 0, 0 };
536 s
= pt_atapi(tape
, id_cmd
, 36, buf
, "identify");
543 printk("%s: Drive %d, unsupported type %d\n",
544 tape
->name
, tape
->drive
, dt
);
555 if (!pt_ready_wait(tape
, PT_READY_TMO
))
556 tape
->flags
|= PT_MEDIA
;
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);
564 if (!pt_atapi(tape
, ls_cmd
, 36, buf
, "log sense"))
565 tape
->capacity
= xn(buf
, 24, 4);
567 printk("%s: %s %s, %s", tape
->name
, mf
, id
, ms
[tape
->drive
]);
568 if (!(tape
->flags
& PT_MEDIA
))
569 printk(", no media\n");
571 if (!(tape
->flags
& PT_WRITE_OK
))
573 printk(", blocksize %d, %d MB\n", tape
->bs
, tape
->capacity
/ 1024);
581 * returns 0, with id set if drive is detected
582 * -1, if drive detection failed
584 static int pt_probe(struct pt_unit
*tape
)
586 if (tape
->drive
== -1) {
587 for (tape
->drive
= 0; tape
->drive
<= 1; tape
->drive
++)
589 return pt_identify(tape
);
592 return pt_identify(tape
);
597 static int pt_detect(void)
599 struct pt_unit
*tape
;
600 int specified
= 0, found
= 0;
603 printk("%s: %s version %s, major %d\n", name
, name
, PT_VERSION
, major
);
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);
611 tape
->last_sense
= 0;
614 tape
->drive
= DU
[D_SLV
];
615 snprintf(tape
->name
, PT_NAMELEN
, "%s%d", name
, unit
);
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
)) {
626 pi_release(tape
->pi
);
629 if (specified
== 0) {
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
)) {
637 pi_release(tape
->pi
);
644 printk("%s: No ATAPI tape drive detected\n", name
);
648 static int pt_open(struct inode
*inode
, struct file
*file
)
650 int unit
= iminor(inode
) & 0x7F;
651 struct pt_unit
*tape
= pt
+ unit
;
655 if (unit
>= PT_UNITS
|| (!tape
->present
)) {
661 if (!atomic_dec_and_test(&tape
->available
))
667 if (!(tape
->flags
& PT_MEDIA
))
671 if ((!(tape
->flags
& PT_WRITE_OK
)) && (file
->f_mode
& FMODE_WRITE
))
674 if (!(iminor(inode
) & 128))
675 tape
->flags
|= PT_REWIND
;
678 tape
->bufptr
= kmalloc(PT_BUFSIZE
, GFP_KERNEL
);
679 if (tape
->bufptr
== NULL
) {
680 printk("%s: buffer allocation failed\n", tape
->name
);
684 file
->private_data
= tape
;
689 atomic_inc(&tape
->available
);
694 static long pt_ioctl(struct file
*file
, unsigned int cmd
, unsigned long arg
)
696 struct pt_unit
*tape
= file
->private_data
;
697 struct mtop __user
*p
= (void __user
*)arg
;
702 if (copy_from_user(&mtop
, p
, sizeof(struct mtop
)))
705 switch (mtop
.mt_op
) {
720 /* FIXME: rate limit ?? */
721 printk(KERN_DEBUG
"%s: Unimplemented mt_op %d\n", tape
->name
,
732 pt_release(struct inode
*inode
, struct file
*file
)
734 struct pt_unit
*tape
= file
->private_data
;
736 if (atomic_read(&tape
->available
) > 1)
739 if (tape
->flags
& PT_WRITING
)
742 if (tape
->flags
& PT_REWIND
)
748 atomic_inc(&tape
->available
);
754 static ssize_t
pt_read(struct file
*filp
, char __user
*buf
, size_t count
, loff_t
* ppos
)
756 struct pt_unit
*tape
= filp
->private_data
;
757 struct pi_adapter
*pi
= tape
->pi
;
758 char rd_cmd
[12] = { ATAPI_READ_6
, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
759 int k
, n
, r
, p
, s
, t
, b
;
761 if (!(tape
->flags
& (PT_READING
| PT_WRITING
))) {
762 tape
->flags
|= PT_READING
;
763 if (pt_atapi(tape
, rd_cmd
, 0, NULL
, "start read-ahead"))
765 } else if (tape
->flags
& PT_WRITING
)
768 if (tape
->flags
& PT_EOF
)
775 if (!pt_poll_dsc(tape
, HZ
/ 100, PT_TMO
, "read"))
780 n
= 32768; /* max per command */
781 b
= (n
- 1 + tape
->bs
) / tape
->bs
;
782 n
= b
* tape
->bs
; /* rounded up to even block */
786 r
= pt_command(tape
, rd_cmd
, n
, "read");
791 pt_req_sense(tape
, 0);
797 r
= pt_wait(tape
, STAT_BUSY
,
798 STAT_DRQ
| STAT_ERR
| STAT_READY
,
799 DBMSG("read DRQ"), "");
801 if (r
& STAT_SENSE
) {
803 pt_req_sense(tape
, 0);
808 tape
->flags
|= PT_EOF
;
815 n
= (read_reg(pi
, 4) + 256 * read_reg(pi
, 5));
816 p
= (read_reg(pi
, 2) & 3);
819 printk("%s: Phase error on read: %d\n", tape
->name
,
828 pi_read_block(pi
, tape
->bufptr
, k
);
833 if (copy_to_user(buf
+ t
, tape
->bufptr
, b
)) {
843 if (tape
->flags
& PT_EOF
)
851 static ssize_t
pt_write(struct file
*filp
, const char __user
*buf
, size_t count
, loff_t
* ppos
)
853 struct pt_unit
*tape
= filp
->private_data
;
854 struct pi_adapter
*pi
= tape
->pi
;
855 char wr_cmd
[12] = { ATAPI_WRITE_6
, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
856 int k
, n
, r
, p
, s
, t
, b
;
858 if (!(tape
->flags
& PT_WRITE_OK
))
861 if (!(tape
->flags
& (PT_READING
| PT_WRITING
))) {
862 tape
->flags
|= PT_WRITING
;
864 (tape
, wr_cmd
, 0, NULL
, "start buffer-available mode"))
866 } else if (tape
->flags
& PT_READING
)
869 if (tape
->flags
& PT_EOF
)
876 if (!pt_poll_dsc(tape
, HZ
/ 100, PT_TMO
, "write"))
881 n
= 32768; /* max per command */
882 b
= (n
- 1 + tape
->bs
) / tape
->bs
;
883 n
= b
* tape
->bs
; /* rounded up to even block */
887 r
= pt_command(tape
, wr_cmd
, n
, "write");
891 if (r
) { /* error delivering command only */
892 pt_req_sense(tape
, 0);
898 r
= pt_wait(tape
, STAT_BUSY
,
899 STAT_DRQ
| STAT_ERR
| STAT_READY
,
900 DBMSG("write DRQ"), NULL
);
902 if (r
& STAT_SENSE
) {
904 pt_req_sense(tape
, 0);
909 tape
->flags
|= PT_EOF
;
916 n
= (read_reg(pi
, 4) + 256 * read_reg(pi
, 5));
917 p
= (read_reg(pi
, 2) & 3);
920 printk("%s: Phase error on write: %d \n",
932 if (copy_from_user(tape
->bufptr
, buf
+ t
, b
)) {
936 pi_write_block(pi
, tape
->bufptr
, k
);
944 if (tape
->flags
& PT_EOF
)
951 static int __init
pt_init(void)
966 err
= register_chrdev(major
, name
, &pt_fops
);
968 printk("pt_init: unable to get major number %d\n", major
);
969 for (unit
= 0; unit
< PT_UNITS
; unit
++)
970 if (pt
[unit
].present
)
971 pi_release(pt
[unit
].pi
);
975 pt_class
= class_create(THIS_MODULE
, "pt");
976 if (IS_ERR(pt_class
)) {
977 err
= PTR_ERR(pt_class
);
981 for (unit
= 0; unit
< PT_UNITS
; unit
++)
982 if (pt
[unit
].present
) {
983 device_create(pt_class
, NULL
, MKDEV(major
, unit
), NULL
,
985 device_create(pt_class
, NULL
, MKDEV(major
, unit
+ 128),
986 NULL
, "pt%dn", unit
);
991 unregister_chrdev(major
, "pt");
996 static void __exit
pt_exit(void)
999 for (unit
= 0; unit
< PT_UNITS
; unit
++)
1000 if (pt
[unit
].present
) {
1001 device_destroy(pt_class
, MKDEV(major
, unit
));
1002 device_destroy(pt_class
, MKDEV(major
, unit
+ 128));
1004 class_destroy(pt_class
);
1005 unregister_chrdev(major
, name
);
1006 for (unit
= 0; unit
< PT_UNITS
; unit
++)
1007 if (pt
[unit
].present
)
1008 pi_release(pt
[unit
].pi
);
1011 MODULE_LICENSE("GPL");
1012 module_init(pt_init
)
1013 module_exit(pt_exit
)