1 From: Peter Osterlund <petero2@telia.com>
2 Subject: Re: [RFC][PATCH] Control pktcdvd with an auxiliary character device
3 To: linux-kernel@vger.kernel.org
4 Cc: Christoph Hellwig <hch@infradead.org>, Arnd Bergmann <arnd@arndb.de>,
5 Jens Axboe <axboe@suse.de>, Andrew Morton <akpm@osdl.org>
6 Date: Wed Jul 14 02:17:27 2004 +0200
8 Peter Osterlund <petero2@telia.com> writes:
10 > Peter Osterlund <petero2@telia.com> writes:
12 > > Christoph Hellwig <hch@infradead.org> writes:
14 > > > On Sun, Jul 11, 2004 at 01:20:45AM +0200, Arnd Bergmann wrote:
15 > > > > These are actually incorrect definitions since the ioctl argument is
16 > > > > not a pointer to unsigned int but instead just an int. However, that's
17 > > > > too late to fix without breaking the existing tools.
19 > > > The tools need to change anyway to get away from the broken behaviour to
20 > > > issue in ioctl on the actual block device to bind it..
22 > > OK, I'll create a patch that gets rid of the ioctl interface and uses
23 > > an auxiliary character device instead to control device bindings.
25 > Here is a patch for 2.6.7-mm7 that does that. The driver creates a
26 > misc character device and bind/unbind of the block devices are
27 > controlled by ioctl commands on the char device.
29 > This patch needs corresponding changes in the pktsetup user space
30 > program. I'll post a patch for pktsetup as a separate message.
32 And here is a patch for udftools-1.0.0b3 that updates the pktsetup
33 program to make it able to use the character device for block device
38 udftools-1.0.0b3-petero/pktsetup/pktsetup.c | 245 +++++++++++++++++++++++++++-
39 1 files changed, 238 insertions(+), 7 deletions(-)
41 diff -puN pktsetup/pktsetup.c~pktsetup-char-dev pktsetup/pktsetup.c
42 --- udftools-1.0.0b3/pktsetup/pktsetup.c~pktsetup-char-dev 2004-07-12 19:57:51.000000000 +0200
43 +++ udftools-1.0.0b3-petero/pktsetup/pktsetup.c 2004-07-14 00:34:02.471317888 +0200
46 * Copyright (c) 1999,2000 Jens Axboe <axboe@suse.de>
47 + * Copyright (c) 2004 Peter Osterlund <petero2@telia.com>
49 * This program is free software; you can redistribute it and/or modify
50 * it under the terms of the GNU General Public License as published by
54 #include <sys/ioctl.h>
55 +#include <sys/stat.h>
58 #include <bits/types.h>
60 #define PACKET_SETUP_DEV _IOW('X', 1, unsigned int)
61 #define PACKET_TEARDOWN_DEV _IOW('X', 2, unsigned int)
63 +#ifndef PACKET_CTRL_CMD
64 +#define PACKET_CTRL_CMD _IOWR('X', 1, struct pkt_ctrl_command)
67 +#define MAJOR(dev) ((dev & 0xfff00) >> 8)
68 +#define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
69 +#define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
71 +#define MISC_MAJOR 10
72 +#define CTL_DIR "/dev/pktcdvd"
73 +#define CTL_DEV "control"
75 +#define PKT_CTRL_CMD_SETUP 0
76 +#define PKT_CTRL_CMD_TEARDOWN 1
77 +#define PKT_CTRL_CMD_STATUS 2
79 +struct pkt_ctrl_command {
80 + __u32 command; /* in: Setup, teardown, status */
81 + __u32 dev_index; /* in/out: Device index */
82 + __u32 dev; /* in/out: Device nr for cdrw device */
83 + __u32 pkt_dev; /* out: Device nr for packet device */
84 + __u32 num_devices; /* out: Largest device index + 1 */
89 -int init_cdrom(int fd)
90 +static int init_cdrom(int fd)
92 if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) < 0) {
93 perror("drive not ready\n");
94 @@ -54,7 +81,7 @@ int init_cdrom(int fd)
98 -void setup_dev(char *pkt_device, char *device, int rem)
99 +static void setup_dev(char *pkt_device, char *device, int rem)
101 int pkt_fd, dev_fd, cmd;
103 @@ -88,29 +115,233 @@ void setup_dev(char *pkt_device, char *d
108 +static int usage(void)
110 - printf("pktsetup /dev/pktcdvd0 /dev/cdrom\tsetup device\n");
111 - printf("pktsetup -d /dev/pktcdvd0\t\ttear down device\n");
112 + printf("For pktcdvd < 0.2.0:\n");
113 + printf(" pktsetup /dev/pktcdvd0 /dev/cdrom setup device\n");
114 + printf(" pktsetup -d /dev/pktcdvd0 tear down device\n");
115 + printf("For pktcdvd >= 0.2.0:\n");
116 + printf(" pktsetup dev_name /dev/cdrom setup device\n");
117 + printf(" pktsetup -d dev_name tear down device\n");
118 + printf(" pktsetup -d major:minor tear down device\n");
119 + printf(" pktsetup -s show device mappings\n");
124 + * Find the minor device number for the pktcdvd control device.
126 +static int get_misc_minor(void)
132 + if ((f = fopen("/proc/misc", "r")) == NULL)
134 + while (fscanf(f, " %d %64s", &minor, name) == 2) {
135 + if (strcmp(name, "pktcdvd") == 0) {
144 +static const char *pkt_dev_name(const char *dev)
146 + static char buf[128];
147 + snprintf(buf, sizeof(buf), "%s/%s", CTL_DIR, dev);
151 +static void create_ctl_dev(void)
154 + struct stat stat_buf;
157 + if ((misc_minor = get_misc_minor()) < 0) {
158 + system("/sbin/modprobe pktcdvd");
159 + misc_minor = get_misc_minor();
161 + if (misc_minor < 0) {
162 + fprintf(stderr, "Can't find pktcdvd character device\n");
165 + dev = MKDEV(MISC_MAJOR, misc_minor);
167 + if ((stat(pkt_dev_name(CTL_DEV), &stat_buf) >= 0) &&
168 + S_ISCHR(stat_buf.st_mode) && (stat_buf.st_rdev == dev))
169 + return; /* Already set up */
171 + mkdir(CTL_DIR, 0755);
172 + unlink(pkt_dev_name(CTL_DEV));
173 + mknod(pkt_dev_name(CTL_DEV), S_IFCHR | 0644, dev);
176 +static int remove_stale_dev_node(int ctl_fd, char *devname)
178 + struct stat stat_buf;
180 + struct pkt_ctrl_command c;
182 + if (stat(pkt_dev_name(devname), &stat_buf) < 0)
184 + if (!S_ISBLK(stat_buf.st_mode))
186 + dev = stat_buf.st_rdev;
187 + memset(&c, 0, sizeof(struct pkt_ctrl_command));
188 + for (i = 0; ; i++) {
189 + c.command = PKT_CTRL_CMD_STATUS;
191 + if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
195 + if (i >= c.num_devices)
197 + if (c.pkt_dev == dev)
198 + return 1; /* busy */
200 + unlink(pkt_dev_name(devname));
204 +static void setup_dev_chardev(char *pkt_device, char *device, int rem)
206 + struct pkt_ctrl_command c;
207 + struct stat stat_buf;
208 + int ctl_fd, dev_fd;
210 + memset(&c, 0, sizeof(struct pkt_ctrl_command));
213 + if ((ctl_fd = open(pkt_dev_name(CTL_DEV), O_RDONLY)) < 0) {
214 + perror("ctl open");
219 + if ((dev_fd = open(device, O_RDONLY | O_NONBLOCK)) == -1) {
220 + perror("open cd-rom");
223 + if (init_cdrom(dev_fd)) {
229 + if (stat(device, &stat_buf) < 0) {
230 + perror("stat cd-rom");
233 + if (!S_ISBLK(stat_buf.st_mode)) {
234 + fprintf(stderr, "Not a block device\n");
237 + c.command = PKT_CTRL_CMD_SETUP;
238 + c.dev = stat_buf.st_rdev;
240 + if (remove_stale_dev_node(ctl_fd, pkt_device) != 0) {
241 + fprintf(stderr, "Device node '%s' already in use\n", pkt_device);
244 + if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
248 + mknod(pkt_dev_name(pkt_device), S_IFBLK | 0640, c.pkt_dev);
250 + int major, minor, remove_node;
252 + if ((stat(pkt_dev_name(pkt_device), &stat_buf) >= 0) &&
253 + S_ISBLK(stat_buf.st_mode)) {
254 + major = MAJOR(stat_buf.st_rdev);
255 + minor = MINOR(stat_buf.st_rdev);
257 + } else if (sscanf(pkt_device, "%d:%d", &major, &minor) == 2) {
260 + fprintf(stderr, "Can't find major/minor numbers\n");
264 + c.command = PKT_CTRL_CMD_TEARDOWN;
265 + c.pkt_dev = MKDEV(major, minor);
266 + if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
271 + unlink(pkt_dev_name(pkt_device));
278 +static void show_mappings(void)
280 + struct pkt_ctrl_command c;
283 + memset(&c, 0, sizeof(struct pkt_ctrl_command));
286 + if ((ctl_fd = open(pkt_dev_name(CTL_DEV), O_RDONLY)) < 0) {
287 + perror("ctl open");
291 + for (i = 0; ; i++) {
292 + c.command = PKT_CTRL_CMD_STATUS;
294 + if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
298 + if (i >= c.num_devices)
301 + printf("%2d : %d:%d -> %d:%d\n",
302 + i, MAJOR(c.pkt_dev), MINOR(c.pkt_dev),
303 + MAJOR(c.dev), MINOR(c.dev));
311 int main(int argc, char **argv)
320 - while ((c = getopt(argc, argv, "d")) != EOF) {
321 + while ((c = getopt(argc, argv, "ds?")) != EOF) {
333 - setup_dev(argv[optind], argv[optind + 1], rem);
334 + pkt_device = argv[optind];
335 + device = argv[optind + 1];
336 + if (strchr(pkt_device, '/'))
337 + setup_dev(pkt_device, device, rem);
339 + setup_dev_chardev(pkt_device, device, rem);
345 Peter Osterlund - petero2@telia.com
346 http://w1.894.telia.com/~u89404340