xref: /OK3568_Linux_fs/kernel/drivers/block/paride/pcd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun 	pcd.c	(c) 1997-8  Grant R. Guenther <grant@torque.net>
3*4882a593Smuzhiyun 		            Under the terms of the GNU General Public License.
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun 	This is a high-level driver for parallel port ATAPI CD-ROM
6*4882a593Smuzhiyun         drives based on chips supported by the paride module.
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun         By default, the driver will autoprobe for a single parallel
9*4882a593Smuzhiyun         port ATAPI CD-ROM drive, but if their individual parameters are
10*4882a593Smuzhiyun         specified, the driver can handle up to 4 drives.
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun         The behaviour of the pcd driver can be altered by setting
13*4882a593Smuzhiyun         some parameters from the insmod command line.  The following
14*4882a593Smuzhiyun         parameters are adjustable:
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun             drive0      These four arguments can be arrays of
17*4882a593Smuzhiyun             drive1      1-6 integers as follows:
18*4882a593Smuzhiyun             drive2
19*4882a593Smuzhiyun             drive3      <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun                         Where,
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun                 <prt>   is the base of the parallel port address for
24*4882a593Smuzhiyun                         the corresponding drive.  (required)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun                 <pro>   is the protocol number for the adapter that
27*4882a593Smuzhiyun                         supports this drive.  These numbers are
28*4882a593Smuzhiyun                         logged by 'paride' when the protocol modules
29*4882a593Smuzhiyun                         are initialised.  (0 if not given)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun                 <uni>   for those adapters that support chained
32*4882a593Smuzhiyun                         devices, this is the unit selector for the
33*4882a593Smuzhiyun                         chain of devices on the given port.  It should
34*4882a593Smuzhiyun                         be zero for devices that don't support chaining.
35*4882a593Smuzhiyun                         (0 if not given)
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun                 <mod>   this can be -1 to choose the best mode, or one
38*4882a593Smuzhiyun                         of the mode numbers supported by the adapter.
39*4882a593Smuzhiyun                         (-1 if not given)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 		<slv>   ATAPI CD-ROMs can be jumpered to master or slave.
42*4882a593Smuzhiyun 			Set this to 0 to choose the master drive, 1 to
43*4882a593Smuzhiyun                         choose the slave, -1 (the default) to choose the
44*4882a593Smuzhiyun 			first drive found.
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun                 <dly>   some parallel ports require the driver to
47*4882a593Smuzhiyun                         go more slowly.  -1 sets a default value that
48*4882a593Smuzhiyun                         should work with the chosen protocol.  Otherwise,
49*4882a593Smuzhiyun                         set this to a small integer, the larger it is
50*4882a593Smuzhiyun                         the slower the port i/o.  In some cases, setting
51*4882a593Smuzhiyun                         this to zero will speed up the device. (default -1)
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun             major       You may use this parameter to override the
54*4882a593Smuzhiyun                         default major number (46) that this driver
55*4882a593Smuzhiyun                         will use.  Be sure to change the device
56*4882a593Smuzhiyun                         name as well.
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun             name        This parameter is a character string that
59*4882a593Smuzhiyun                         contains the name the kernel will use for this
60*4882a593Smuzhiyun                         device (in /proc output, for instance).
61*4882a593Smuzhiyun                         (default "pcd")
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun             verbose     This parameter controls the amount of logging
64*4882a593Smuzhiyun                         that the driver will do.  Set it to 0 for
65*4882a593Smuzhiyun                         normal operation, 1 to see autoprobe progress
66*4882a593Smuzhiyun                         messages, or 2 to see additional debugging
67*4882a593Smuzhiyun                         output.  (default 0)
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun             nice        This parameter controls the driver's use of
70*4882a593Smuzhiyun                         idle CPU time, at the expense of some speed.
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	If this driver is built into the kernel, you can use the
73*4882a593Smuzhiyun         following kernel command line parameters, with the same values
74*4882a593Smuzhiyun         as the corresponding module parameters listed above:
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	    pcd.drive0
77*4882a593Smuzhiyun 	    pcd.drive1
78*4882a593Smuzhiyun 	    pcd.drive2
79*4882a593Smuzhiyun 	    pcd.drive3
80*4882a593Smuzhiyun 	    pcd.nice
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun         In addition, you can use the parameter pcd.disable to disable
83*4882a593Smuzhiyun         the driver entirely.
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /* Changes:
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	1.01	GRG 1998.01.24	Added test unit ready support
90*4882a593Smuzhiyun 	1.02    GRG 1998.05.06  Changes to pcd_completion, ready_wait,
91*4882a593Smuzhiyun 				and loosen interpretation of ATAPI
92*4882a593Smuzhiyun 			        standard for clearing error status.
93*4882a593Smuzhiyun 				Use spinlocks. Eliminate sti().
94*4882a593Smuzhiyun 	1.03    GRG 1998.06.16  Eliminated an Ugh
95*4882a593Smuzhiyun 	1.04	GRG 1998.08.15  Added extra debugging, improvements to
96*4882a593Smuzhiyun 				pcd_completion, use HZ in loop timing
97*4882a593Smuzhiyun 	1.05	GRG 1998.08.16	Conformed to "Uniform CD-ROM" standard
98*4882a593Smuzhiyun 	1.06    GRG 1998.08.19  Added audio ioctl support
99*4882a593Smuzhiyun 	1.07    GRG 1998.09.24  Increased reset timeout, added jumbo support
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun */
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #define	PCD_VERSION	"1.07"
104*4882a593Smuzhiyun #define PCD_MAJOR	46
105*4882a593Smuzhiyun #define PCD_NAME	"pcd"
106*4882a593Smuzhiyun #define PCD_UNITS	4
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /* Here are things one can override from the insmod command.
109*4882a593Smuzhiyun    Most are autoprobed by paride unless set here.  Verbose is off
110*4882a593Smuzhiyun    by default.
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun */
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun static int verbose = 0;
115*4882a593Smuzhiyun static int major = PCD_MAJOR;
116*4882a593Smuzhiyun static char *name = PCD_NAME;
117*4882a593Smuzhiyun static int nice = 0;
118*4882a593Smuzhiyun static int disable = 0;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
121*4882a593Smuzhiyun static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
122*4882a593Smuzhiyun static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
123*4882a593Smuzhiyun static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
126*4882a593Smuzhiyun static int pcd_drive_count;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun /* end of parameters */
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun #include <linux/module.h>
133*4882a593Smuzhiyun #include <linux/init.h>
134*4882a593Smuzhiyun #include <linux/errno.h>
135*4882a593Smuzhiyun #include <linux/fs.h>
136*4882a593Smuzhiyun #include <linux/kernel.h>
137*4882a593Smuzhiyun #include <linux/delay.h>
138*4882a593Smuzhiyun #include <linux/cdrom.h>
139*4882a593Smuzhiyun #include <linux/spinlock.h>
140*4882a593Smuzhiyun #include <linux/blk-mq.h>
141*4882a593Smuzhiyun #include <linux/mutex.h>
142*4882a593Smuzhiyun #include <linux/uaccess.h>
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static DEFINE_MUTEX(pcd_mutex);
145*4882a593Smuzhiyun static DEFINE_SPINLOCK(pcd_lock);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun module_param(verbose, int, 0644);
148*4882a593Smuzhiyun module_param(major, int, 0);
149*4882a593Smuzhiyun module_param(name, charp, 0);
150*4882a593Smuzhiyun module_param(nice, int, 0);
151*4882a593Smuzhiyun module_param_array(drive0, int, NULL, 0);
152*4882a593Smuzhiyun module_param_array(drive1, int, NULL, 0);
153*4882a593Smuzhiyun module_param_array(drive2, int, NULL, 0);
154*4882a593Smuzhiyun module_param_array(drive3, int, NULL, 0);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun #include "paride.h"
157*4882a593Smuzhiyun #include "pseudo.h"
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun #define PCD_RETRIES	     5
160*4882a593Smuzhiyun #define PCD_TMO		   800	/* timeout in jiffies */
161*4882a593Smuzhiyun #define PCD_DELAY           50	/* spin delay in uS */
162*4882a593Smuzhiyun #define PCD_READY_TMO	    20	/* in seconds */
163*4882a593Smuzhiyun #define PCD_RESET_TMO	   100	/* in tenths of a second */
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun #define PCD_SPIN	(1000000*PCD_TMO)/(HZ*PCD_DELAY)
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun #define IDE_ERR		0x01
168*4882a593Smuzhiyun #define IDE_DRQ         0x08
169*4882a593Smuzhiyun #define IDE_READY       0x40
170*4882a593Smuzhiyun #define IDE_BUSY        0x80
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun static int pcd_open(struct cdrom_device_info *cdi, int purpose);
173*4882a593Smuzhiyun static void pcd_release(struct cdrom_device_info *cdi);
174*4882a593Smuzhiyun static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
175*4882a593Smuzhiyun static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
176*4882a593Smuzhiyun 				     unsigned int clearing, int slot_nr);
177*4882a593Smuzhiyun static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
178*4882a593Smuzhiyun static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
179*4882a593Smuzhiyun static int pcd_drive_reset(struct cdrom_device_info *cdi);
180*4882a593Smuzhiyun static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
181*4882a593Smuzhiyun static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
182*4882a593Smuzhiyun 			   unsigned int cmd, void *arg);
183*4882a593Smuzhiyun static int pcd_packet(struct cdrom_device_info *cdi,
184*4882a593Smuzhiyun 		      struct packet_command *cgc);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun static int pcd_detect(void);
187*4882a593Smuzhiyun static void pcd_probe_capabilities(void);
188*4882a593Smuzhiyun static void do_pcd_read_drq(void);
189*4882a593Smuzhiyun static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
190*4882a593Smuzhiyun 				 const struct blk_mq_queue_data *bd);
191*4882a593Smuzhiyun static void do_pcd_read(void);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun struct pcd_unit {
194*4882a593Smuzhiyun 	struct pi_adapter pia;	/* interface to paride layer */
195*4882a593Smuzhiyun 	struct pi_adapter *pi;
196*4882a593Smuzhiyun 	int drive;		/* master/slave */
197*4882a593Smuzhiyun 	int last_sense;		/* result of last request sense */
198*4882a593Smuzhiyun 	int changed;		/* media change seen */
199*4882a593Smuzhiyun 	int present;		/* does this unit exist ? */
200*4882a593Smuzhiyun 	char *name;		/* pcd0, pcd1, etc */
201*4882a593Smuzhiyun 	struct cdrom_device_info info;	/* uniform cdrom interface */
202*4882a593Smuzhiyun 	struct gendisk *disk;
203*4882a593Smuzhiyun 	struct blk_mq_tag_set tag_set;
204*4882a593Smuzhiyun 	struct list_head rq_list;
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static struct pcd_unit pcd[PCD_UNITS];
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun static char pcd_scratch[64];
210*4882a593Smuzhiyun static char pcd_buffer[2048];	/* raw block buffer */
211*4882a593Smuzhiyun static int pcd_bufblk = -1;	/* block in buffer, in CD units,
212*4882a593Smuzhiyun 				   -1 for nothing there. See also
213*4882a593Smuzhiyun 				   pd_unit.
214*4882a593Smuzhiyun 				 */
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun /* the variables below are used mainly in the I/O request engine, which
217*4882a593Smuzhiyun    processes only one request at a time.
218*4882a593Smuzhiyun */
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun static struct pcd_unit *pcd_current; /* current request's drive */
221*4882a593Smuzhiyun static struct request *pcd_req;
222*4882a593Smuzhiyun static int pcd_retries;		/* retries on current request */
223*4882a593Smuzhiyun static int pcd_busy;		/* request being processed ? */
224*4882a593Smuzhiyun static int pcd_sector;		/* address of next requested sector */
225*4882a593Smuzhiyun static int pcd_count;		/* number of blocks still to do */
226*4882a593Smuzhiyun static char *pcd_buf;		/* buffer for request in progress */
227*4882a593Smuzhiyun static void *par_drv;		/* reference of parport driver */
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun /* kernel glue structures */
230*4882a593Smuzhiyun 
pcd_block_open(struct block_device * bdev,fmode_t mode)231*4882a593Smuzhiyun static int pcd_block_open(struct block_device *bdev, fmode_t mode)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct pcd_unit *cd = bdev->bd_disk->private_data;
234*4882a593Smuzhiyun 	int ret;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	bdev_check_media_change(bdev);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	mutex_lock(&pcd_mutex);
239*4882a593Smuzhiyun 	ret = cdrom_open(&cd->info, bdev, mode);
240*4882a593Smuzhiyun 	mutex_unlock(&pcd_mutex);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	return ret;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
pcd_block_release(struct gendisk * disk,fmode_t mode)245*4882a593Smuzhiyun static void pcd_block_release(struct gendisk *disk, fmode_t mode)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	struct pcd_unit *cd = disk->private_data;
248*4882a593Smuzhiyun 	mutex_lock(&pcd_mutex);
249*4882a593Smuzhiyun 	cdrom_release(&cd->info, mode);
250*4882a593Smuzhiyun 	mutex_unlock(&pcd_mutex);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
pcd_block_ioctl(struct block_device * bdev,fmode_t mode,unsigned cmd,unsigned long arg)253*4882a593Smuzhiyun static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode,
254*4882a593Smuzhiyun 				unsigned cmd, unsigned long arg)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	struct pcd_unit *cd = bdev->bd_disk->private_data;
257*4882a593Smuzhiyun 	int ret;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	mutex_lock(&pcd_mutex);
260*4882a593Smuzhiyun 	ret = cdrom_ioctl(&cd->info, bdev, mode, cmd, arg);
261*4882a593Smuzhiyun 	mutex_unlock(&pcd_mutex);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return ret;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
pcd_block_check_events(struct gendisk * disk,unsigned int clearing)266*4882a593Smuzhiyun static unsigned int pcd_block_check_events(struct gendisk *disk,
267*4882a593Smuzhiyun 					   unsigned int clearing)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	struct pcd_unit *cd = disk->private_data;
270*4882a593Smuzhiyun 	return cdrom_check_events(&cd->info, clearing);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun static const struct block_device_operations pcd_bdops = {
274*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
275*4882a593Smuzhiyun 	.open		= pcd_block_open,
276*4882a593Smuzhiyun 	.release	= pcd_block_release,
277*4882a593Smuzhiyun 	.ioctl		= pcd_block_ioctl,
278*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
279*4882a593Smuzhiyun 	.compat_ioctl	= blkdev_compat_ptr_ioctl,
280*4882a593Smuzhiyun #endif
281*4882a593Smuzhiyun 	.check_events	= pcd_block_check_events,
282*4882a593Smuzhiyun };
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun static const struct cdrom_device_ops pcd_dops = {
285*4882a593Smuzhiyun 	.open		= pcd_open,
286*4882a593Smuzhiyun 	.release	= pcd_release,
287*4882a593Smuzhiyun 	.drive_status	= pcd_drive_status,
288*4882a593Smuzhiyun 	.check_events	= pcd_check_events,
289*4882a593Smuzhiyun 	.tray_move	= pcd_tray_move,
290*4882a593Smuzhiyun 	.lock_door	= pcd_lock_door,
291*4882a593Smuzhiyun 	.get_mcn	= pcd_get_mcn,
292*4882a593Smuzhiyun 	.reset		= pcd_drive_reset,
293*4882a593Smuzhiyun 	.audio_ioctl	= pcd_audio_ioctl,
294*4882a593Smuzhiyun 	.generic_packet	= pcd_packet,
295*4882a593Smuzhiyun 	.capability	= CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
296*4882a593Smuzhiyun 			  CDC_MCN | CDC_MEDIA_CHANGED | CDC_RESET |
297*4882a593Smuzhiyun 			  CDC_PLAY_AUDIO | CDC_GENERIC_PACKET | CDC_CD_R |
298*4882a593Smuzhiyun 			  CDC_CD_RW,
299*4882a593Smuzhiyun };
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun static const struct blk_mq_ops pcd_mq_ops = {
302*4882a593Smuzhiyun 	.queue_rq	= pcd_queue_rq,
303*4882a593Smuzhiyun };
304*4882a593Smuzhiyun 
pcd_init_units(void)305*4882a593Smuzhiyun static void pcd_init_units(void)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	struct pcd_unit *cd;
308*4882a593Smuzhiyun 	int unit;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	pcd_drive_count = 0;
311*4882a593Smuzhiyun 	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
312*4882a593Smuzhiyun 		struct gendisk *disk = alloc_disk(1);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 		if (!disk)
315*4882a593Smuzhiyun 			continue;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 		disk->queue = blk_mq_init_sq_queue(&cd->tag_set, &pcd_mq_ops,
318*4882a593Smuzhiyun 						   1, BLK_MQ_F_SHOULD_MERGE);
319*4882a593Smuzhiyun 		if (IS_ERR(disk->queue)) {
320*4882a593Smuzhiyun 			disk->queue = NULL;
321*4882a593Smuzhiyun 			put_disk(disk);
322*4882a593Smuzhiyun 			continue;
323*4882a593Smuzhiyun 		}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 		INIT_LIST_HEAD(&cd->rq_list);
326*4882a593Smuzhiyun 		disk->queue->queuedata = cd;
327*4882a593Smuzhiyun 		blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
328*4882a593Smuzhiyun 		cd->disk = disk;
329*4882a593Smuzhiyun 		cd->pi = &cd->pia;
330*4882a593Smuzhiyun 		cd->present = 0;
331*4882a593Smuzhiyun 		cd->last_sense = 0;
332*4882a593Smuzhiyun 		cd->changed = 1;
333*4882a593Smuzhiyun 		cd->drive = (*drives[unit])[D_SLV];
334*4882a593Smuzhiyun 		if ((*drives[unit])[D_PRT])
335*4882a593Smuzhiyun 			pcd_drive_count++;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 		cd->name = &cd->info.name[0];
338*4882a593Smuzhiyun 		snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit);
339*4882a593Smuzhiyun 		cd->info.ops = &pcd_dops;
340*4882a593Smuzhiyun 		cd->info.handle = cd;
341*4882a593Smuzhiyun 		cd->info.speed = 0;
342*4882a593Smuzhiyun 		cd->info.capacity = 1;
343*4882a593Smuzhiyun 		cd->info.mask = 0;
344*4882a593Smuzhiyun 		disk->major = major;
345*4882a593Smuzhiyun 		disk->first_minor = unit;
346*4882a593Smuzhiyun 		strcpy(disk->disk_name, cd->name);	/* umm... */
347*4882a593Smuzhiyun 		disk->fops = &pcd_bdops;
348*4882a593Smuzhiyun 		disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
349*4882a593Smuzhiyun 		disk->events = DISK_EVENT_MEDIA_CHANGE;
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
pcd_open(struct cdrom_device_info * cdi,int purpose)353*4882a593Smuzhiyun static int pcd_open(struct cdrom_device_info *cdi, int purpose)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	struct pcd_unit *cd = cdi->handle;
356*4882a593Smuzhiyun 	if (!cd->present)
357*4882a593Smuzhiyun 		return -ENODEV;
358*4882a593Smuzhiyun 	return 0;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
pcd_release(struct cdrom_device_info * cdi)361*4882a593Smuzhiyun static void pcd_release(struct cdrom_device_info *cdi)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
status_reg(struct pcd_unit * cd)365*4882a593Smuzhiyun static inline int status_reg(struct pcd_unit *cd)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	return pi_read_regr(cd->pi, 1, 6);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
read_reg(struct pcd_unit * cd,int reg)370*4882a593Smuzhiyun static inline int read_reg(struct pcd_unit *cd, int reg)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	return pi_read_regr(cd->pi, 0, reg);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
write_reg(struct pcd_unit * cd,int reg,int val)375*4882a593Smuzhiyun static inline void write_reg(struct pcd_unit *cd, int reg, int val)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	pi_write_regr(cd->pi, 0, reg, val);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
pcd_wait(struct pcd_unit * cd,int go,int stop,char * fun,char * msg)380*4882a593Smuzhiyun static int pcd_wait(struct pcd_unit *cd, int go, int stop, char *fun, char *msg)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	int j, r, e, s, p;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	j = 0;
385*4882a593Smuzhiyun 	while ((((r = status_reg(cd)) & go) || (stop && (!(r & stop))))
386*4882a593Smuzhiyun 	       && (j++ < PCD_SPIN))
387*4882a593Smuzhiyun 		udelay(PCD_DELAY);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	if ((r & (IDE_ERR & stop)) || (j > PCD_SPIN)) {
390*4882a593Smuzhiyun 		s = read_reg(cd, 7);
391*4882a593Smuzhiyun 		e = read_reg(cd, 1);
392*4882a593Smuzhiyun 		p = read_reg(cd, 2);
393*4882a593Smuzhiyun 		if (j > PCD_SPIN)
394*4882a593Smuzhiyun 			e |= 0x100;
395*4882a593Smuzhiyun 		if (fun)
396*4882a593Smuzhiyun 			printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
397*4882a593Smuzhiyun 			       " loop=%d phase=%d\n",
398*4882a593Smuzhiyun 			       cd->name, fun, msg, r, s, e, j, p);
399*4882a593Smuzhiyun 		return (s << 8) + r;
400*4882a593Smuzhiyun 	}
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
pcd_command(struct pcd_unit * cd,char * cmd,int dlen,char * fun)404*4882a593Smuzhiyun static int pcd_command(struct pcd_unit *cd, char *cmd, int dlen, char *fun)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	pi_connect(cd->pi);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	if (pcd_wait(cd, IDE_BUSY | IDE_DRQ, 0, fun, "before command")) {
411*4882a593Smuzhiyun 		pi_disconnect(cd->pi);
412*4882a593Smuzhiyun 		return -1;
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	write_reg(cd, 4, dlen % 256);
416*4882a593Smuzhiyun 	write_reg(cd, 5, dlen / 256);
417*4882a593Smuzhiyun 	write_reg(cd, 7, 0xa0);	/* ATAPI packet command */
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	if (pcd_wait(cd, IDE_BUSY, IDE_DRQ, fun, "command DRQ")) {
420*4882a593Smuzhiyun 		pi_disconnect(cd->pi);
421*4882a593Smuzhiyun 		return -1;
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	if (read_reg(cd, 2) != 1) {
425*4882a593Smuzhiyun 		printk("%s: %s: command phase error\n", cd->name, fun);
426*4882a593Smuzhiyun 		pi_disconnect(cd->pi);
427*4882a593Smuzhiyun 		return -1;
428*4882a593Smuzhiyun 	}
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	pi_write_block(cd->pi, cmd, 12);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	return 0;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
pcd_completion(struct pcd_unit * cd,char * buf,char * fun)435*4882a593Smuzhiyun static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	int r, d, p, n, k, j;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	r = -1;
440*4882a593Smuzhiyun 	k = 0;
441*4882a593Smuzhiyun 	j = 0;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	if (!pcd_wait(cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR,
444*4882a593Smuzhiyun 		      fun, "completion")) {
445*4882a593Smuzhiyun 		r = 0;
446*4882a593Smuzhiyun 		while (read_reg(cd, 7) & IDE_DRQ) {
447*4882a593Smuzhiyun 			d = read_reg(cd, 4) + 256 * read_reg(cd, 5);
448*4882a593Smuzhiyun 			n = (d + 3) & 0xfffc;
449*4882a593Smuzhiyun 			p = read_reg(cd, 2) & 3;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 			if ((p == 2) && (n > 0) && (j == 0)) {
452*4882a593Smuzhiyun 				pi_read_block(cd->pi, buf, n);
453*4882a593Smuzhiyun 				if (verbose > 1)
454*4882a593Smuzhiyun 					printk("%s: %s: Read %d bytes\n",
455*4882a593Smuzhiyun 					       cd->name, fun, n);
456*4882a593Smuzhiyun 				r = 0;
457*4882a593Smuzhiyun 				j++;
458*4882a593Smuzhiyun 			} else {
459*4882a593Smuzhiyun 				if (verbose > 1)
460*4882a593Smuzhiyun 					printk
461*4882a593Smuzhiyun 					    ("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
462*4882a593Smuzhiyun 					     cd->name, fun, p, d, k);
463*4882a593Smuzhiyun 				if (verbose < 2)
464*4882a593Smuzhiyun 					printk_once(
465*4882a593Smuzhiyun 					    "%s: WARNING: ATAPI phase errors\n",
466*4882a593Smuzhiyun 					    cd->name);
467*4882a593Smuzhiyun 				mdelay(1);
468*4882a593Smuzhiyun 			}
469*4882a593Smuzhiyun 			if (k++ > PCD_TMO) {
470*4882a593Smuzhiyun 				printk("%s: Stuck DRQ\n", cd->name);
471*4882a593Smuzhiyun 				break;
472*4882a593Smuzhiyun 			}
473*4882a593Smuzhiyun 			if (pcd_wait
474*4882a593Smuzhiyun 			    (cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR, fun,
475*4882a593Smuzhiyun 			     "completion")) {
476*4882a593Smuzhiyun 				r = -1;
477*4882a593Smuzhiyun 				break;
478*4882a593Smuzhiyun 			}
479*4882a593Smuzhiyun 		}
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	pi_disconnect(cd->pi);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	return r;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
pcd_req_sense(struct pcd_unit * cd,char * fun)487*4882a593Smuzhiyun static void pcd_req_sense(struct pcd_unit *cd, char *fun)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun 	char rs_cmd[12] = { 0x03, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
490*4882a593Smuzhiyun 	char buf[16];
491*4882a593Smuzhiyun 	int r, c;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	r = pcd_command(cd, rs_cmd, 16, "Request sense");
494*4882a593Smuzhiyun 	mdelay(1);
495*4882a593Smuzhiyun 	if (!r)
496*4882a593Smuzhiyun 		pcd_completion(cd, buf, "Request sense");
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	cd->last_sense = -1;
499*4882a593Smuzhiyun 	c = 2;
500*4882a593Smuzhiyun 	if (!r) {
501*4882a593Smuzhiyun 		if (fun)
502*4882a593Smuzhiyun 			printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
503*4882a593Smuzhiyun 			       cd->name, fun, buf[2] & 0xf, buf[12], buf[13]);
504*4882a593Smuzhiyun 		c = buf[2] & 0xf;
505*4882a593Smuzhiyun 		cd->last_sense =
506*4882a593Smuzhiyun 		    c | ((buf[12] & 0xff) << 8) | ((buf[13] & 0xff) << 16);
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun 	if ((c == 2) || (c == 6))
509*4882a593Smuzhiyun 		cd->changed = 1;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun 
pcd_atapi(struct pcd_unit * cd,char * cmd,int dlen,char * buf,char * fun)512*4882a593Smuzhiyun static int pcd_atapi(struct pcd_unit *cd, char *cmd, int dlen, char *buf, char *fun)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun 	int r;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	r = pcd_command(cd, cmd, dlen, fun);
517*4882a593Smuzhiyun 	mdelay(1);
518*4882a593Smuzhiyun 	if (!r)
519*4882a593Smuzhiyun 		r = pcd_completion(cd, buf, fun);
520*4882a593Smuzhiyun 	if (r)
521*4882a593Smuzhiyun 		pcd_req_sense(cd, fun);
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	return r;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
pcd_packet(struct cdrom_device_info * cdi,struct packet_command * cgc)526*4882a593Smuzhiyun static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun 	return pcd_atapi(cdi->handle, cgc->cmd, cgc->buflen, cgc->buffer,
529*4882a593Smuzhiyun 			 "generic packet");
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun #define DBMSG(msg)	((verbose>1)?(msg):NULL)
533*4882a593Smuzhiyun 
pcd_check_events(struct cdrom_device_info * cdi,unsigned int clearing,int slot_nr)534*4882a593Smuzhiyun static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
535*4882a593Smuzhiyun 				     unsigned int clearing, int slot_nr)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	struct pcd_unit *cd = cdi->handle;
538*4882a593Smuzhiyun 	int res = cd->changed;
539*4882a593Smuzhiyun 	if (res)
540*4882a593Smuzhiyun 		cd->changed = 0;
541*4882a593Smuzhiyun 	return res ? DISK_EVENT_MEDIA_CHANGE : 0;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
pcd_lock_door(struct cdrom_device_info * cdi,int lock)544*4882a593Smuzhiyun static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	char un_cmd[12] = { 0x1e, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0 };
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	return pcd_atapi(cdi->handle, un_cmd, 0, pcd_scratch,
549*4882a593Smuzhiyun 			 lock ? "lock door" : "unlock door");
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun 
pcd_tray_move(struct cdrom_device_info * cdi,int position)552*4882a593Smuzhiyun static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	char ej_cmd[12] = { 0x1b, 0, 0, 0, 3 - position, 0, 0, 0, 0, 0, 0, 0 };
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	return pcd_atapi(cdi->handle, ej_cmd, 0, pcd_scratch,
557*4882a593Smuzhiyun 			 position ? "eject" : "close tray");
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
pcd_sleep(int cs)560*4882a593Smuzhiyun static void pcd_sleep(int cs)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	schedule_timeout_interruptible(cs);
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun 
pcd_reset(struct pcd_unit * cd)565*4882a593Smuzhiyun static int pcd_reset(struct pcd_unit *cd)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun 	int i, k, flg;
568*4882a593Smuzhiyun 	int expect[5] = { 1, 1, 1, 0x14, 0xeb };
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	pi_connect(cd->pi);
571*4882a593Smuzhiyun 	write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
572*4882a593Smuzhiyun 	write_reg(cd, 7, 8);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	pcd_sleep(20 * HZ / 1000);	/* delay a bit */
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	k = 0;
577*4882a593Smuzhiyun 	while ((k++ < PCD_RESET_TMO) && (status_reg(cd) & IDE_BUSY))
578*4882a593Smuzhiyun 		pcd_sleep(HZ / 10);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	flg = 1;
581*4882a593Smuzhiyun 	for (i = 0; i < 5; i++)
582*4882a593Smuzhiyun 		flg &= (read_reg(cd, i + 1) == expect[i]);
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	if (verbose) {
585*4882a593Smuzhiyun 		printk("%s: Reset (%d) signature = ", cd->name, k);
586*4882a593Smuzhiyun 		for (i = 0; i < 5; i++)
587*4882a593Smuzhiyun 			printk("%3x", read_reg(cd, i + 1));
588*4882a593Smuzhiyun 		if (!flg)
589*4882a593Smuzhiyun 			printk(" (incorrect)");
590*4882a593Smuzhiyun 		printk("\n");
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	pi_disconnect(cd->pi);
594*4882a593Smuzhiyun 	return flg - 1;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
pcd_drive_reset(struct cdrom_device_info * cdi)597*4882a593Smuzhiyun static int pcd_drive_reset(struct cdrom_device_info *cdi)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	return pcd_reset(cdi->handle);
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
pcd_ready_wait(struct pcd_unit * cd,int tmo)602*4882a593Smuzhiyun static int pcd_ready_wait(struct pcd_unit *cd, int tmo)
603*4882a593Smuzhiyun {
604*4882a593Smuzhiyun 	char tr_cmd[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
605*4882a593Smuzhiyun 	int k, p;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	k = 0;
608*4882a593Smuzhiyun 	while (k < tmo) {
609*4882a593Smuzhiyun 		cd->last_sense = 0;
610*4882a593Smuzhiyun 		pcd_atapi(cd, tr_cmd, 0, NULL, DBMSG("test unit ready"));
611*4882a593Smuzhiyun 		p = cd->last_sense;
612*4882a593Smuzhiyun 		if (!p)
613*4882a593Smuzhiyun 			return 0;
614*4882a593Smuzhiyun 		if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
615*4882a593Smuzhiyun 			return p;
616*4882a593Smuzhiyun 		k++;
617*4882a593Smuzhiyun 		pcd_sleep(HZ);
618*4882a593Smuzhiyun 	}
619*4882a593Smuzhiyun 	return 0x000020;	/* timeout */
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun 
pcd_drive_status(struct cdrom_device_info * cdi,int slot_nr)622*4882a593Smuzhiyun static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun 	char rc_cmd[12] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
625*4882a593Smuzhiyun 	struct pcd_unit *cd = cdi->handle;
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	if (pcd_ready_wait(cd, PCD_READY_TMO))
628*4882a593Smuzhiyun 		return CDS_DRIVE_NOT_READY;
629*4882a593Smuzhiyun 	if (pcd_atapi(cd, rc_cmd, 8, pcd_scratch, DBMSG("check media")))
630*4882a593Smuzhiyun 		return CDS_NO_DISC;
631*4882a593Smuzhiyun 	return CDS_DISC_OK;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun 
pcd_identify(struct pcd_unit * cd,char * id)634*4882a593Smuzhiyun static int pcd_identify(struct pcd_unit *cd, char *id)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	int k, s;
637*4882a593Smuzhiyun 	char id_cmd[12] = { 0x12, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	pcd_bufblk = -1;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	s = pcd_atapi(cd, id_cmd, 36, pcd_buffer, "identify");
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	if (s)
644*4882a593Smuzhiyun 		return -1;
645*4882a593Smuzhiyun 	if ((pcd_buffer[0] & 0x1f) != 5) {
646*4882a593Smuzhiyun 		if (verbose)
647*4882a593Smuzhiyun 			printk("%s: %s is not a CD-ROM\n",
648*4882a593Smuzhiyun 			       cd->name, cd->drive ? "Slave" : "Master");
649*4882a593Smuzhiyun 		return -1;
650*4882a593Smuzhiyun 	}
651*4882a593Smuzhiyun 	memcpy(id, pcd_buffer + 16, 16);
652*4882a593Smuzhiyun 	id[16] = 0;
653*4882a593Smuzhiyun 	k = 16;
654*4882a593Smuzhiyun 	while ((k >= 0) && (id[k] <= 0x20)) {
655*4882a593Smuzhiyun 		id[k] = 0;
656*4882a593Smuzhiyun 		k--;
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	printk("%s: %s: %s\n", cd->name, cd->drive ? "Slave" : "Master", id);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun /*
665*4882a593Smuzhiyun  * returns  0, with id set if drive is detected
666*4882a593Smuzhiyun  *	    -1, if drive detection failed
667*4882a593Smuzhiyun  */
pcd_probe(struct pcd_unit * cd,int ms,char * id)668*4882a593Smuzhiyun static int pcd_probe(struct pcd_unit *cd, int ms, char *id)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	if (ms == -1) {
671*4882a593Smuzhiyun 		for (cd->drive = 0; cd->drive <= 1; cd->drive++)
672*4882a593Smuzhiyun 			if (!pcd_reset(cd) && !pcd_identify(cd, id))
673*4882a593Smuzhiyun 				return 0;
674*4882a593Smuzhiyun 	} else {
675*4882a593Smuzhiyun 		cd->drive = ms;
676*4882a593Smuzhiyun 		if (!pcd_reset(cd) && !pcd_identify(cd, id))
677*4882a593Smuzhiyun 			return 0;
678*4882a593Smuzhiyun 	}
679*4882a593Smuzhiyun 	return -1;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
pcd_probe_capabilities(void)682*4882a593Smuzhiyun static void pcd_probe_capabilities(void)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	int unit, r;
685*4882a593Smuzhiyun 	char buffer[32];
686*4882a593Smuzhiyun 	char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 };
687*4882a593Smuzhiyun 	struct pcd_unit *cd;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
690*4882a593Smuzhiyun 		if (!cd->present)
691*4882a593Smuzhiyun 			continue;
692*4882a593Smuzhiyun 		r = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
693*4882a593Smuzhiyun 		if (r)
694*4882a593Smuzhiyun 			continue;
695*4882a593Smuzhiyun 		/* we should now have the cap page */
696*4882a593Smuzhiyun 		if ((buffer[11] & 1) == 0)
697*4882a593Smuzhiyun 			cd->info.mask |= CDC_CD_R;
698*4882a593Smuzhiyun 		if ((buffer[11] & 2) == 0)
699*4882a593Smuzhiyun 			cd->info.mask |= CDC_CD_RW;
700*4882a593Smuzhiyun 		if ((buffer[12] & 1) == 0)
701*4882a593Smuzhiyun 			cd->info.mask |= CDC_PLAY_AUDIO;
702*4882a593Smuzhiyun 		if ((buffer[14] & 1) == 0)
703*4882a593Smuzhiyun 			cd->info.mask |= CDC_LOCK;
704*4882a593Smuzhiyun 		if ((buffer[14] & 8) == 0)
705*4882a593Smuzhiyun 			cd->info.mask |= CDC_OPEN_TRAY;
706*4882a593Smuzhiyun 		if ((buffer[14] >> 6) == 0)
707*4882a593Smuzhiyun 			cd->info.mask |= CDC_CLOSE_TRAY;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
pcd_detect(void)711*4882a593Smuzhiyun static int pcd_detect(void)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun 	char id[18];
714*4882a593Smuzhiyun 	int k, unit;
715*4882a593Smuzhiyun 	struct pcd_unit *cd;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	printk("%s: %s version %s, major %d, nice %d\n",
718*4882a593Smuzhiyun 	       name, name, PCD_VERSION, major, nice);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	par_drv = pi_register_driver(name);
721*4882a593Smuzhiyun 	if (!par_drv) {
722*4882a593Smuzhiyun 		pr_err("failed to register %s driver\n", name);
723*4882a593Smuzhiyun 		return -1;
724*4882a593Smuzhiyun 	}
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	k = 0;
727*4882a593Smuzhiyun 	if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
728*4882a593Smuzhiyun 		cd = pcd;
729*4882a593Smuzhiyun 		if (cd->disk && pi_init(cd->pi, 1, -1, -1, -1, -1, -1,
730*4882a593Smuzhiyun 			    pcd_buffer, PI_PCD, verbose, cd->name)) {
731*4882a593Smuzhiyun 			if (!pcd_probe(cd, -1, id)) {
732*4882a593Smuzhiyun 				cd->present = 1;
733*4882a593Smuzhiyun 				k++;
734*4882a593Smuzhiyun 			} else
735*4882a593Smuzhiyun 				pi_release(cd->pi);
736*4882a593Smuzhiyun 		}
737*4882a593Smuzhiyun 	} else {
738*4882a593Smuzhiyun 		for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
739*4882a593Smuzhiyun 			int *conf = *drives[unit];
740*4882a593Smuzhiyun 			if (!conf[D_PRT])
741*4882a593Smuzhiyun 				continue;
742*4882a593Smuzhiyun 			if (!cd->disk)
743*4882a593Smuzhiyun 				continue;
744*4882a593Smuzhiyun 			if (!pi_init(cd->pi, 0, conf[D_PRT], conf[D_MOD],
745*4882a593Smuzhiyun 				     conf[D_UNI], conf[D_PRO], conf[D_DLY],
746*4882a593Smuzhiyun 				     pcd_buffer, PI_PCD, verbose, cd->name))
747*4882a593Smuzhiyun 				continue;
748*4882a593Smuzhiyun 			if (!pcd_probe(cd, conf[D_SLV], id)) {
749*4882a593Smuzhiyun 				cd->present = 1;
750*4882a593Smuzhiyun 				k++;
751*4882a593Smuzhiyun 			} else
752*4882a593Smuzhiyun 				pi_release(cd->pi);
753*4882a593Smuzhiyun 		}
754*4882a593Smuzhiyun 	}
755*4882a593Smuzhiyun 	if (k)
756*4882a593Smuzhiyun 		return 0;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	printk("%s: No CD-ROM drive found\n", name);
759*4882a593Smuzhiyun 	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
760*4882a593Smuzhiyun 		if (!cd->disk)
761*4882a593Smuzhiyun 			continue;
762*4882a593Smuzhiyun 		blk_cleanup_queue(cd->disk->queue);
763*4882a593Smuzhiyun 		cd->disk->queue = NULL;
764*4882a593Smuzhiyun 		blk_mq_free_tag_set(&cd->tag_set);
765*4882a593Smuzhiyun 		put_disk(cd->disk);
766*4882a593Smuzhiyun 	}
767*4882a593Smuzhiyun 	pi_unregister_driver(par_drv);
768*4882a593Smuzhiyun 	return -1;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun /* I/O request processing */
772*4882a593Smuzhiyun static int pcd_queue;
773*4882a593Smuzhiyun 
set_next_request(void)774*4882a593Smuzhiyun static int set_next_request(void)
775*4882a593Smuzhiyun {
776*4882a593Smuzhiyun 	struct pcd_unit *cd;
777*4882a593Smuzhiyun 	int old_pos = pcd_queue;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	do {
780*4882a593Smuzhiyun 		cd = &pcd[pcd_queue];
781*4882a593Smuzhiyun 		if (++pcd_queue == PCD_UNITS)
782*4882a593Smuzhiyun 			pcd_queue = 0;
783*4882a593Smuzhiyun 		if (cd->present && !list_empty(&cd->rq_list)) {
784*4882a593Smuzhiyun 			pcd_req = list_first_entry(&cd->rq_list, struct request,
785*4882a593Smuzhiyun 							queuelist);
786*4882a593Smuzhiyun 			list_del_init(&pcd_req->queuelist);
787*4882a593Smuzhiyun 			blk_mq_start_request(pcd_req);
788*4882a593Smuzhiyun 			break;
789*4882a593Smuzhiyun 		}
790*4882a593Smuzhiyun 	} while (pcd_queue != old_pos);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	return pcd_req != NULL;
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun 
pcd_request(void)795*4882a593Smuzhiyun static void pcd_request(void)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun 	struct pcd_unit *cd;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	if (pcd_busy)
800*4882a593Smuzhiyun 		return;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	if (!pcd_req && !set_next_request())
803*4882a593Smuzhiyun 		return;
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	cd = pcd_req->rq_disk->private_data;
806*4882a593Smuzhiyun 	if (cd != pcd_current)
807*4882a593Smuzhiyun 		pcd_bufblk = -1;
808*4882a593Smuzhiyun 	pcd_current = cd;
809*4882a593Smuzhiyun 	pcd_sector = blk_rq_pos(pcd_req);
810*4882a593Smuzhiyun 	pcd_count = blk_rq_cur_sectors(pcd_req);
811*4882a593Smuzhiyun 	pcd_buf = bio_data(pcd_req->bio);
812*4882a593Smuzhiyun 	pcd_busy = 1;
813*4882a593Smuzhiyun 	ps_set_intr(do_pcd_read, NULL, 0, nice);
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun 
pcd_queue_rq(struct blk_mq_hw_ctx * hctx,const struct blk_mq_queue_data * bd)816*4882a593Smuzhiyun static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
817*4882a593Smuzhiyun 				 const struct blk_mq_queue_data *bd)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun 	struct pcd_unit *cd = hctx->queue->queuedata;
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	if (rq_data_dir(bd->rq) != READ) {
822*4882a593Smuzhiyun 		blk_mq_start_request(bd->rq);
823*4882a593Smuzhiyun 		return BLK_STS_IOERR;
824*4882a593Smuzhiyun 	}
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	spin_lock_irq(&pcd_lock);
827*4882a593Smuzhiyun 	list_add_tail(&bd->rq->queuelist, &cd->rq_list);
828*4882a593Smuzhiyun 	pcd_request();
829*4882a593Smuzhiyun 	spin_unlock_irq(&pcd_lock);
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	return BLK_STS_OK;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun 
next_request(blk_status_t err)834*4882a593Smuzhiyun static inline void next_request(blk_status_t err)
835*4882a593Smuzhiyun {
836*4882a593Smuzhiyun 	unsigned long saved_flags;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	spin_lock_irqsave(&pcd_lock, saved_flags);
839*4882a593Smuzhiyun 	if (!blk_update_request(pcd_req, err, blk_rq_cur_bytes(pcd_req))) {
840*4882a593Smuzhiyun 		__blk_mq_end_request(pcd_req, err);
841*4882a593Smuzhiyun 		pcd_req = NULL;
842*4882a593Smuzhiyun 	}
843*4882a593Smuzhiyun 	pcd_busy = 0;
844*4882a593Smuzhiyun 	pcd_request();
845*4882a593Smuzhiyun 	spin_unlock_irqrestore(&pcd_lock, saved_flags);
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun 
pcd_ready(void)848*4882a593Smuzhiyun static int pcd_ready(void)
849*4882a593Smuzhiyun {
850*4882a593Smuzhiyun 	return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ));
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
pcd_transfer(void)853*4882a593Smuzhiyun static void pcd_transfer(void)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) {
857*4882a593Smuzhiyun 		int o = (pcd_sector % 4) * 512;
858*4882a593Smuzhiyun 		memcpy(pcd_buf, pcd_buffer + o, 512);
859*4882a593Smuzhiyun 		pcd_count--;
860*4882a593Smuzhiyun 		pcd_buf += 512;
861*4882a593Smuzhiyun 		pcd_sector++;
862*4882a593Smuzhiyun 	}
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun 
pcd_start(void)865*4882a593Smuzhiyun static void pcd_start(void)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun 	int b, i;
868*4882a593Smuzhiyun 	char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	pcd_bufblk = pcd_sector / 4;
871*4882a593Smuzhiyun 	b = pcd_bufblk;
872*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
873*4882a593Smuzhiyun 		rd_cmd[5 - i] = b & 0xff;
874*4882a593Smuzhiyun 		b = b >> 8;
875*4882a593Smuzhiyun 	}
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) {
878*4882a593Smuzhiyun 		pcd_bufblk = -1;
879*4882a593Smuzhiyun 		next_request(BLK_STS_IOERR);
880*4882a593Smuzhiyun 		return;
881*4882a593Smuzhiyun 	}
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	mdelay(1);
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice);
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun 
do_pcd_read(void)888*4882a593Smuzhiyun static void do_pcd_read(void)
889*4882a593Smuzhiyun {
890*4882a593Smuzhiyun 	pcd_busy = 1;
891*4882a593Smuzhiyun 	pcd_retries = 0;
892*4882a593Smuzhiyun 	pcd_transfer();
893*4882a593Smuzhiyun 	if (!pcd_count) {
894*4882a593Smuzhiyun 		next_request(0);
895*4882a593Smuzhiyun 		return;
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	pi_do_claimed(pcd_current->pi, pcd_start);
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun 
do_pcd_read_drq(void)901*4882a593Smuzhiyun static void do_pcd_read_drq(void)
902*4882a593Smuzhiyun {
903*4882a593Smuzhiyun 	unsigned long saved_flags;
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	if (pcd_completion(pcd_current, pcd_buffer, "read block")) {
906*4882a593Smuzhiyun 		if (pcd_retries < PCD_RETRIES) {
907*4882a593Smuzhiyun 			mdelay(1);
908*4882a593Smuzhiyun 			pcd_retries++;
909*4882a593Smuzhiyun 			pi_do_claimed(pcd_current->pi, pcd_start);
910*4882a593Smuzhiyun 			return;
911*4882a593Smuzhiyun 		}
912*4882a593Smuzhiyun 		pcd_bufblk = -1;
913*4882a593Smuzhiyun 		next_request(BLK_STS_IOERR);
914*4882a593Smuzhiyun 		return;
915*4882a593Smuzhiyun 	}
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	do_pcd_read();
918*4882a593Smuzhiyun 	spin_lock_irqsave(&pcd_lock, saved_flags);
919*4882a593Smuzhiyun 	pcd_request();
920*4882a593Smuzhiyun 	spin_unlock_irqrestore(&pcd_lock, saved_flags);
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun /* the audio_ioctl stuff is adapted from sr_ioctl.c */
924*4882a593Smuzhiyun 
pcd_audio_ioctl(struct cdrom_device_info * cdi,unsigned int cmd,void * arg)925*4882a593Smuzhiyun static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
926*4882a593Smuzhiyun {
927*4882a593Smuzhiyun 	struct pcd_unit *cd = cdi->handle;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	switch (cmd) {
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	case CDROMREADTOCHDR:
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 		{
934*4882a593Smuzhiyun 			char cmd[12] =
935*4882a593Smuzhiyun 			    { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
936*4882a593Smuzhiyun 			 0, 0, 0 };
937*4882a593Smuzhiyun 			struct cdrom_tochdr *tochdr =
938*4882a593Smuzhiyun 			    (struct cdrom_tochdr *) arg;
939*4882a593Smuzhiyun 			char buffer[32];
940*4882a593Smuzhiyun 			int r;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 			r = pcd_atapi(cd, cmd, 12, buffer, "read toc header");
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 			tochdr->cdth_trk0 = buffer[2];
945*4882a593Smuzhiyun 			tochdr->cdth_trk1 = buffer[3];
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 			return r ? -EIO : 0;
948*4882a593Smuzhiyun 		}
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	case CDROMREADTOCENTRY:
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 		{
953*4882a593Smuzhiyun 			char cmd[12] =
954*4882a593Smuzhiyun 			    { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
955*4882a593Smuzhiyun 			 0, 0, 0 };
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 			struct cdrom_tocentry *tocentry =
958*4882a593Smuzhiyun 			    (struct cdrom_tocentry *) arg;
959*4882a593Smuzhiyun 			unsigned char buffer[32];
960*4882a593Smuzhiyun 			int r;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 			cmd[1] =
963*4882a593Smuzhiyun 			    (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
964*4882a593Smuzhiyun 			cmd[6] = tocentry->cdte_track;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 			r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry");
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 			tocentry->cdte_ctrl = buffer[5] & 0xf;
969*4882a593Smuzhiyun 			tocentry->cdte_adr = buffer[5] >> 4;
970*4882a593Smuzhiyun 			tocentry->cdte_datamode =
971*4882a593Smuzhiyun 			    (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
972*4882a593Smuzhiyun 			if (tocentry->cdte_format == CDROM_MSF) {
973*4882a593Smuzhiyun 				tocentry->cdte_addr.msf.minute = buffer[9];
974*4882a593Smuzhiyun 				tocentry->cdte_addr.msf.second = buffer[10];
975*4882a593Smuzhiyun 				tocentry->cdte_addr.msf.frame = buffer[11];
976*4882a593Smuzhiyun 			} else
977*4882a593Smuzhiyun 				tocentry->cdte_addr.lba =
978*4882a593Smuzhiyun 				    (((((buffer[8] << 8) + buffer[9]) << 8)
979*4882a593Smuzhiyun 				      + buffer[10]) << 8) + buffer[11];
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 			return r ? -EIO : 0;
982*4882a593Smuzhiyun 		}
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	default:
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 		return -ENOSYS;
987*4882a593Smuzhiyun 	}
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun 
pcd_get_mcn(struct cdrom_device_info * cdi,struct cdrom_mcn * mcn)990*4882a593Smuzhiyun static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun 	char cmd[12] =
993*4882a593Smuzhiyun 	    { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 };
994*4882a593Smuzhiyun 	char buffer[32];
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn"))
997*4882a593Smuzhiyun 		return -EIO;
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
1000*4882a593Smuzhiyun 	mcn->medium_catalog_number[13] = 0;
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	return 0;
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun 
pcd_init(void)1005*4882a593Smuzhiyun static int __init pcd_init(void)
1006*4882a593Smuzhiyun {
1007*4882a593Smuzhiyun 	struct pcd_unit *cd;
1008*4882a593Smuzhiyun 	int unit;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	if (disable)
1011*4882a593Smuzhiyun 		return -EINVAL;
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	pcd_init_units();
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	if (pcd_detect())
1016*4882a593Smuzhiyun 		return -ENODEV;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	/* get the atapi capabilities page */
1019*4882a593Smuzhiyun 	pcd_probe_capabilities();
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	if (register_blkdev(major, name)) {
1022*4882a593Smuzhiyun 		for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
1023*4882a593Smuzhiyun 			if (!cd->disk)
1024*4882a593Smuzhiyun 				continue;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 			blk_cleanup_queue(cd->disk->queue);
1027*4882a593Smuzhiyun 			blk_mq_free_tag_set(&cd->tag_set);
1028*4882a593Smuzhiyun 			put_disk(cd->disk);
1029*4882a593Smuzhiyun 		}
1030*4882a593Smuzhiyun 		return -EBUSY;
1031*4882a593Smuzhiyun 	}
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
1034*4882a593Smuzhiyun 		if (cd->present) {
1035*4882a593Smuzhiyun 			register_cdrom(cd->disk, &cd->info);
1036*4882a593Smuzhiyun 			cd->disk->private_data = cd;
1037*4882a593Smuzhiyun 			add_disk(cd->disk);
1038*4882a593Smuzhiyun 		}
1039*4882a593Smuzhiyun 	}
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	return 0;
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun 
pcd_exit(void)1044*4882a593Smuzhiyun static void __exit pcd_exit(void)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun 	struct pcd_unit *cd;
1047*4882a593Smuzhiyun 	int unit;
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
1050*4882a593Smuzhiyun 		if (!cd->disk)
1051*4882a593Smuzhiyun 			continue;
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 		if (cd->present) {
1054*4882a593Smuzhiyun 			del_gendisk(cd->disk);
1055*4882a593Smuzhiyun 			pi_release(cd->pi);
1056*4882a593Smuzhiyun 			unregister_cdrom(&cd->info);
1057*4882a593Smuzhiyun 		}
1058*4882a593Smuzhiyun 		blk_cleanup_queue(cd->disk->queue);
1059*4882a593Smuzhiyun 		blk_mq_free_tag_set(&cd->tag_set);
1060*4882a593Smuzhiyun 		put_disk(cd->disk);
1061*4882a593Smuzhiyun 	}
1062*4882a593Smuzhiyun 	unregister_blkdev(major, name);
1063*4882a593Smuzhiyun 	pi_unregister_driver(par_drv);
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1067*4882a593Smuzhiyun module_init(pcd_init)
1068*4882a593Smuzhiyun module_exit(pcd_exit)
1069