- supported.conf: Added sparse_keymap (eeepc_laptop depends on it)
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / blkback / cdrom.c
1 /******************************************************************************
2  * blkback/cdrom.c
3  *
4  * Routines for managing cdrom watch and media-present attribute of a
5  * cdrom type virtual block device (VBD).
6  *
7  * Copyright (c) 2003-2005, Keir Fraser & Steve Hand
8  * Copyright (c) 2007       Pat Campbell
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License version 2
12  * as published by the Free Software Foundation; or, when distributed
13  * separately from the Linux kernel or incorporated into other
14  * software packages, subject to the following license:
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a copy
17  * of this source file (the "Software"), to deal in the Software without
18  * restriction, including without limitation the rights to use, copy, modify,
19  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
20  * and to permit persons to whom the Software is furnished to do so, subject to
21  * the following conditions:
22  *
23  * The above copyright notice and this permission notice shall be included in
24  * all copies or substantial portions of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32  * IN THE SOFTWARE.
33  */
34
35 #include "common.h"
36
37 #undef DPRINTK
38 #define DPRINTK(_f, _a...)                      \
39         printk("(%s() file=%s, line=%d) " _f "\n",      \
40                  __PRETTY_FUNCTION__, __FILE__ , __LINE__ , ##_a )
41
42
43 #define MEDIA_PRESENT "media-present"
44
45 static void cdrom_media_changed(struct xenbus_watch *, const char **, unsigned int);
46
47 /**
48  * Writes media-present=1 attribute for the given vbd device if not
49  * already there
50  */
51 static int cdrom_xenstore_write_media_present(struct backend_info *be)
52 {
53         struct xenbus_device *dev = be->dev;
54         struct xenbus_transaction xbt;
55         int err;
56         int media_present;
57
58         err = xenbus_scanf(XBT_NIL, dev->nodename, MEDIA_PRESENT, "%d",
59                            &media_present);
60         if (0 < err) {
61                 DPRINTK("already written err%d", err);
62                 return(0);
63         }
64         media_present = 1;
65
66 again:
67         err = xenbus_transaction_start(&xbt);
68         if (err) {
69                 xenbus_dev_fatal(dev, err, "starting transaction");
70                 return(-1);
71         }
72
73         err = xenbus_printf(xbt, dev->nodename, MEDIA_PRESENT, "%d", media_present );
74         if (err) {
75                 xenbus_dev_fatal(dev, err, "writing %s/%s",
76                          dev->nodename, MEDIA_PRESENT);
77                 goto abort;
78         }
79         err = xenbus_transaction_end(xbt, 0);
80         if (err == -EAGAIN)
81                 goto again;
82         if (err)
83                 xenbus_dev_fatal(dev, err, "ending transaction");
84         return 0;
85  abort:
86         xenbus_transaction_end(xbt, 1);
87         return -1;
88 }
89
90 /**
91  *
92  */
93 static int cdrom_is_type(struct backend_info *be)
94 {
95         DPRINTK("type:%x", be->blkif->vbd.type );
96         return (be->blkif->vbd.type & VDISK_CDROM)
97                && (be->blkif->vbd.type & GENHD_FL_REMOVABLE);
98 }
99
100 /**
101  *
102  */
103 void cdrom_add_media_watch(struct backend_info *be)
104 {
105         struct xenbus_device *dev = be->dev;
106         int err;
107
108         DPRINTK("nodename:%s", dev->nodename);
109         if (cdrom_is_type(be)) {
110                 DPRINTK("is a cdrom");
111                 if ( cdrom_xenstore_write_media_present(be) == 0 ) {
112                         DPRINTK( "xenstore wrote OK");
113                         err = xenbus_watch_path2(dev, dev->nodename, MEDIA_PRESENT,
114                                                  &be->backend_cdrom_watch,
115                                                  cdrom_media_changed);
116                         if (err)
117                                 DPRINTK( "media_present watch add failed" );
118                 }
119         }
120 }
121
122 /**
123  * Callback received when the "media_present" xenstore node is changed
124  */
125 static void cdrom_media_changed(struct xenbus_watch *watch,
126                                 const char **vec, unsigned int len)
127 {
128         int err;
129         unsigned media_present;
130         struct backend_info *be
131                 = container_of(watch, struct backend_info, backend_cdrom_watch);
132         struct xenbus_device *dev = be->dev;
133
134         if (!cdrom_is_type(be)) {
135                 DPRINTK("callback not for a cdrom" );
136                 return;
137         }
138
139         err = xenbus_scanf(XBT_NIL, dev->nodename, MEDIA_PRESENT, "%d",
140                            &media_present);
141         if (err == 0 || err == -ENOENT) {
142                 DPRINTK("xenbus_read of cdrom media_present node error:%d",err);
143                 return;
144         }
145
146         if (media_present == 0)
147                 vbd_free(&be->blkif->vbd);
148         else {
149                 char *p = strrchr(dev->otherend, '/') + 1;
150                 long handle = simple_strtoul(p, NULL, 0);
151
152                 if (!be->blkif->vbd.bdev) {
153                         err = vbd_create(be->blkif, handle, be->major, be->minor,
154                                          !strchr(be->mode, 'w'), 1);
155                         if (err) {
156                                 be->major = be->minor = 0;
157                                 xenbus_dev_fatal(dev, err, "creating vbd structure");
158                                 return;
159                         }
160                 }
161         }
162 }