Merge branches 'oprofile-v2' and 'timers/hpet' into x86/core-v4
[linux-2.6] / drivers / s390 / cio / chsc_sch.c
1 /*
2  * Driver for s390 chsc subchannels
3  *
4  * Copyright IBM Corp. 2008
5  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6  *
7  */
8
9 #include <linux/device.h>
10 #include <linux/module.h>
11 #include <linux/uaccess.h>
12 #include <linux/miscdevice.h>
13
14 #include <asm/cio.h>
15 #include <asm/chsc.h>
16 #include <asm/isc.h>
17
18 #include "cio.h"
19 #include "cio_debug.h"
20 #include "css.h"
21 #include "chsc_sch.h"
22 #include "ioasm.h"
23
24 static debug_info_t *chsc_debug_msg_id;
25 static debug_info_t *chsc_debug_log_id;
26
27 #define CHSC_MSG(imp, args...) do {                                     \
28                 debug_sprintf_event(chsc_debug_msg_id, imp , ##args);   \
29         } while (0)
30
31 #define CHSC_LOG(imp, txt) do {                                 \
32                 debug_text_event(chsc_debug_log_id, imp , txt); \
33         } while (0)
34
35 static void CHSC_LOG_HEX(int level, void *data, int length)
36 {
37         while (length > 0) {
38                 debug_event(chsc_debug_log_id, level, data, length);
39                 length -= chsc_debug_log_id->buf_size;
40                 data += chsc_debug_log_id->buf_size;
41         }
42 }
43
44 MODULE_AUTHOR("IBM Corporation");
45 MODULE_DESCRIPTION("driver for s390 chsc subchannels");
46 MODULE_LICENSE("GPL");
47
48 static void chsc_subchannel_irq(struct subchannel *sch)
49 {
50         struct chsc_private *private = sch->private;
51         struct chsc_request *request = private->request;
52         struct irb *irb = (struct irb *)__LC_IRB;
53
54         CHSC_LOG(4, "irb");
55         CHSC_LOG_HEX(4, irb, sizeof(*irb));
56         /* Copy irb to provided request and set done. */
57         if (!request) {
58                 CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n",
59                          sch->schid.ssid, sch->schid.sch_no);
60                 return;
61         }
62         private->request = NULL;
63         memcpy(&request->irb, irb, sizeof(*irb));
64         stsch(sch->schid, &sch->schib);
65         complete(&request->completion);
66         put_device(&sch->dev);
67 }
68
69 static int chsc_subchannel_probe(struct subchannel *sch)
70 {
71         struct chsc_private *private;
72         int ret;
73
74         CHSC_MSG(6, "Detected chsc subchannel 0.%x.%04x\n",
75                  sch->schid.ssid, sch->schid.sch_no);
76         sch->isc = CHSC_SCH_ISC;
77         private = kzalloc(sizeof(*private), GFP_KERNEL);
78         if (!private)
79                 return -ENOMEM;
80         ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
81         if (ret) {
82                 CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n",
83                          sch->schid.ssid, sch->schid.sch_no, ret);
84                 kfree(private);
85         } else {
86                 sch->private = private;
87                 if (sch->dev.uevent_suppress) {
88                         sch->dev.uevent_suppress = 0;
89                         kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
90                 }
91         }
92         return ret;
93 }
94
95 static int chsc_subchannel_remove(struct subchannel *sch)
96 {
97         struct chsc_private *private;
98
99         cio_disable_subchannel(sch);
100         private = sch->private;
101         sch->private = NULL;
102         if (private->request) {
103                 complete(&private->request->completion);
104                 put_device(&sch->dev);
105         }
106         kfree(private);
107         return 0;
108 }
109
110 static void chsc_subchannel_shutdown(struct subchannel *sch)
111 {
112         cio_disable_subchannel(sch);
113 }
114
115 static struct css_device_id chsc_subchannel_ids[] = {
116         { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, },
117         { /* end of list */ },
118 };
119 MODULE_DEVICE_TABLE(css, chsc_subchannel_ids);
120
121 static struct css_driver chsc_subchannel_driver = {
122         .owner = THIS_MODULE,
123         .subchannel_type = chsc_subchannel_ids,
124         .irq = chsc_subchannel_irq,
125         .probe = chsc_subchannel_probe,
126         .remove = chsc_subchannel_remove,
127         .shutdown = chsc_subchannel_shutdown,
128         .name = "chsc_subchannel",
129 };
130
131 static int __init chsc_init_dbfs(void)
132 {
133         chsc_debug_msg_id = debug_register("chsc_msg", 16, 1,
134                                            16 * sizeof(long));
135         if (!chsc_debug_msg_id)
136                 goto out;
137         debug_register_view(chsc_debug_msg_id, &debug_sprintf_view);
138         debug_set_level(chsc_debug_msg_id, 2);
139         chsc_debug_log_id = debug_register("chsc_log", 16, 1, 16);
140         if (!chsc_debug_log_id)
141                 goto out;
142         debug_register_view(chsc_debug_log_id, &debug_hex_ascii_view);
143         debug_set_level(chsc_debug_log_id, 2);
144         return 0;
145 out:
146         if (chsc_debug_msg_id)
147                 debug_unregister(chsc_debug_msg_id);
148         return -ENOMEM;
149 }
150
151 static void chsc_remove_dbfs(void)
152 {
153         debug_unregister(chsc_debug_log_id);
154         debug_unregister(chsc_debug_msg_id);
155 }
156
157 static int __init chsc_init_sch_driver(void)
158 {
159         return css_driver_register(&chsc_subchannel_driver);
160 }
161
162 static void chsc_cleanup_sch_driver(void)
163 {
164         css_driver_unregister(&chsc_subchannel_driver);
165 }
166
167 static DEFINE_SPINLOCK(chsc_lock);
168
169 static int chsc_subchannel_match_next_free(struct device *dev, void *data)
170 {
171         struct subchannel *sch = to_subchannel(dev);
172
173         return sch->schib.pmcw.ena && !scsw_fctl(&sch->schib.scsw);
174 }
175
176 static struct subchannel *chsc_get_next_subchannel(struct subchannel *sch)
177 {
178         struct device *dev;
179
180         dev = driver_find_device(&chsc_subchannel_driver.drv,
181                                  sch ? &sch->dev : NULL, NULL,
182                                  chsc_subchannel_match_next_free);
183         return dev ? to_subchannel(dev) : NULL;
184 }
185
186 /**
187  * chsc_async() - try to start a chsc request asynchronously
188  * @chsc_area: request to be started
189  * @request: request structure to associate
190  *
191  * Tries to start a chsc request on one of the existing chsc subchannels.
192  * Returns:
193  *  %0 if the request was performed synchronously
194  *  %-EINPROGRESS if the request was successfully started
195  *  %-EBUSY if all chsc subchannels are busy
196  *  %-ENODEV if no chsc subchannels are available
197  * Context:
198  *  interrupts disabled, chsc_lock held
199  */
200 static int chsc_async(struct chsc_async_area *chsc_area,
201                       struct chsc_request *request)
202 {
203         int cc;
204         struct chsc_private *private;
205         struct subchannel *sch = NULL;
206         int ret = -ENODEV;
207         char dbf[10];
208
209         chsc_area->header.key = PAGE_DEFAULT_KEY;
210         while ((sch = chsc_get_next_subchannel(sch))) {
211                 spin_lock(sch->lock);
212                 private = sch->private;
213                 if (private->request) {
214                         spin_unlock(sch->lock);
215                         ret = -EBUSY;
216                         continue;
217                 }
218                 chsc_area->header.sid = sch->schid;
219                 CHSC_LOG(2, "schid");
220                 CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid));
221                 cc = chsc(chsc_area);
222                 sprintf(dbf, "cc:%d", cc);
223                 CHSC_LOG(2, dbf);
224                 switch (cc) {
225                 case 0:
226                         ret = 0;
227                         break;
228                 case 1:
229                         sch->schib.scsw.cmd.fctl |= SCSW_FCTL_START_FUNC;
230                         ret = -EINPROGRESS;
231                         private->request = request;
232                         break;
233                 case 2:
234                         ret = -EBUSY;
235                         break;
236                 default:
237                         ret = -ENODEV;
238                 }
239                 spin_unlock(sch->lock);
240                 CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n",
241                          sch->schid.ssid, sch->schid.sch_no, cc);
242                 if (ret == -EINPROGRESS)
243                         return -EINPROGRESS;
244                 put_device(&sch->dev);
245                 if (ret == 0)
246                         return 0;
247         }
248         return ret;
249 }
250
251 static void chsc_log_command(struct chsc_async_area *chsc_area)
252 {
253         char dbf[10];
254
255         sprintf(dbf, "CHSC:%x", chsc_area->header.code);
256         CHSC_LOG(0, dbf);
257         CHSC_LOG_HEX(0, chsc_area, 32);
258 }
259
260 static int chsc_examine_irb(struct chsc_request *request)
261 {
262         int backed_up;
263
264         if (!(scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND))
265                 return -EIO;
266         backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK;
267         request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK;
268         if (scsw_cstat(&request->irb.scsw) == 0)
269                 return 0;
270         if (!backed_up)
271                 return 0;
272         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROG_CHECK)
273                 return -EIO;
274         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROT_CHECK)
275                 return -EPERM;
276         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_DATA_CHK)
277                 return -EAGAIN;
278         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_CTRL_CHK)
279                 return -EAGAIN;
280         return -EIO;
281 }
282
283 static int chsc_ioctl_start(void __user *user_area)
284 {
285         struct chsc_request *request;
286         struct chsc_async_area *chsc_area;
287         int ret;
288         char dbf[10];
289
290         if (!css_general_characteristics.dynio)
291                 /* It makes no sense to try. */
292                 return -EOPNOTSUPP;
293         chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
294         if (!chsc_area)
295                 return -ENOMEM;
296         request = kzalloc(sizeof(*request), GFP_KERNEL);
297         if (!request) {
298                 ret = -ENOMEM;
299                 goto out_free;
300         }
301         init_completion(&request->completion);
302         if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
303                 ret = -EFAULT;
304                 goto out_free;
305         }
306         chsc_log_command(chsc_area);
307         spin_lock_irq(&chsc_lock);
308         ret = chsc_async(chsc_area, request);
309         spin_unlock_irq(&chsc_lock);
310         if (ret == -EINPROGRESS) {
311                 wait_for_completion(&request->completion);
312                 ret = chsc_examine_irb(request);
313         }
314         /* copy area back to user */
315         if (!ret)
316                 if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
317                         ret = -EFAULT;
318 out_free:
319         sprintf(dbf, "ret:%d", ret);
320         CHSC_LOG(0, dbf);
321         kfree(request);
322         free_page((unsigned long)chsc_area);
323         return ret;
324 }
325
326 static int chsc_ioctl_info_channel_path(void __user *user_cd)
327 {
328         struct chsc_chp_cd *cd;
329         int ret, ccode;
330         struct {
331                 struct chsc_header request;
332                 u32 : 2;
333                 u32 m : 1;
334                 u32 : 1;
335                 u32 fmt1 : 4;
336                 u32 cssid : 8;
337                 u32 : 8;
338                 u32 first_chpid : 8;
339                 u32 : 24;
340                 u32 last_chpid : 8;
341                 u32 : 32;
342                 struct chsc_header response;
343                 u8 data[PAGE_SIZE - 20];
344         } __attribute__ ((packed)) *scpcd_area;
345
346         scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
347         if (!scpcd_area)
348                 return -ENOMEM;
349         cd = kzalloc(sizeof(*cd), GFP_KERNEL);
350         if (!cd) {
351                 ret = -ENOMEM;
352                 goto out_free;
353         }
354         if (copy_from_user(cd, user_cd, sizeof(*cd))) {
355                 ret = -EFAULT;
356                 goto out_free;
357         }
358         scpcd_area->request.length = 0x0010;
359         scpcd_area->request.code = 0x0028;
360         scpcd_area->m = cd->m;
361         scpcd_area->fmt1 = cd->fmt;
362         scpcd_area->cssid = cd->chpid.cssid;
363         scpcd_area->first_chpid = cd->chpid.id;
364         scpcd_area->last_chpid = cd->chpid.id;
365
366         ccode = chsc(scpcd_area);
367         if (ccode != 0) {
368                 ret = -EIO;
369                 goto out_free;
370         }
371         if (scpcd_area->response.code != 0x0001) {
372                 ret = -EIO;
373                 CHSC_MSG(0, "scpcd: response code=%x\n",
374                          scpcd_area->response.code);
375                 goto out_free;
376         }
377         memcpy(&cd->cpcb, &scpcd_area->response, scpcd_area->response.length);
378         if (copy_to_user(user_cd, cd, sizeof(*cd)))
379                 ret = -EFAULT;
380         else
381                 ret = 0;
382 out_free:
383         kfree(cd);
384         free_page((unsigned long)scpcd_area);
385         return ret;
386 }
387
388 static int chsc_ioctl_info_cu(void __user *user_cd)
389 {
390         struct chsc_cu_cd *cd;
391         int ret, ccode;
392         struct {
393                 struct chsc_header request;
394                 u32 : 2;
395                 u32 m : 1;
396                 u32 : 1;
397                 u32 fmt1 : 4;
398                 u32 cssid : 8;
399                 u32 : 8;
400                 u32 first_cun : 8;
401                 u32 : 24;
402                 u32 last_cun : 8;
403                 u32 : 32;
404                 struct chsc_header response;
405                 u8 data[PAGE_SIZE - 20];
406         } __attribute__ ((packed)) *scucd_area;
407
408         scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
409         if (!scucd_area)
410                 return -ENOMEM;
411         cd = kzalloc(sizeof(*cd), GFP_KERNEL);
412         if (!cd) {
413                 ret = -ENOMEM;
414                 goto out_free;
415         }
416         if (copy_from_user(cd, user_cd, sizeof(*cd))) {
417                 ret = -EFAULT;
418                 goto out_free;
419         }
420         scucd_area->request.length = 0x0010;
421         scucd_area->request.code = 0x0028;
422         scucd_area->m = cd->m;
423         scucd_area->fmt1 = cd->fmt;
424         scucd_area->cssid = cd->cssid;
425         scucd_area->first_cun = cd->cun;
426         scucd_area->last_cun = cd->cun;
427
428         ccode = chsc(scucd_area);
429         if (ccode != 0) {
430                 ret = -EIO;
431                 goto out_free;
432         }
433         if (scucd_area->response.code != 0x0001) {
434                 ret = -EIO;
435                 CHSC_MSG(0, "scucd: response code=%x\n",
436                          scucd_area->response.code);
437                 goto out_free;
438         }
439         memcpy(&cd->cucb, &scucd_area->response, scucd_area->response.length);
440         if (copy_to_user(user_cd, cd, sizeof(*cd)))
441                 ret = -EFAULT;
442         else
443                 ret = 0;
444 out_free:
445         kfree(cd);
446         free_page((unsigned long)scucd_area);
447         return ret;
448 }
449
450 static int chsc_ioctl_info_sch_cu(void __user *user_cud)
451 {
452         struct chsc_sch_cud *cud;
453         int ret, ccode;
454         struct {
455                 struct chsc_header request;
456                 u32 : 2;
457                 u32 m : 1;
458                 u32 : 5;
459                 u32 fmt1 : 4;
460                 u32 : 2;
461                 u32 ssid : 2;
462                 u32 first_sch : 16;
463                 u32 : 8;
464                 u32 cssid : 8;
465                 u32 last_sch : 16;
466                 u32 : 32;
467                 struct chsc_header response;
468                 u8 data[PAGE_SIZE - 20];
469         } __attribute__ ((packed)) *sscud_area;
470
471         sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
472         if (!sscud_area)
473                 return -ENOMEM;
474         cud = kzalloc(sizeof(*cud), GFP_KERNEL);
475         if (!cud) {
476                 ret = -ENOMEM;
477                 goto out_free;
478         }
479         if (copy_from_user(cud, user_cud, sizeof(*cud))) {
480                 ret = -EFAULT;
481                 goto out_free;
482         }
483         sscud_area->request.length = 0x0010;
484         sscud_area->request.code = 0x0006;
485         sscud_area->m = cud->schid.m;
486         sscud_area->fmt1 = cud->fmt;
487         sscud_area->ssid = cud->schid.ssid;
488         sscud_area->first_sch = cud->schid.sch_no;
489         sscud_area->cssid = cud->schid.cssid;
490         sscud_area->last_sch = cud->schid.sch_no;
491
492         ccode = chsc(sscud_area);
493         if (ccode != 0) {
494                 ret = -EIO;
495                 goto out_free;
496         }
497         if (sscud_area->response.code != 0x0001) {
498                 ret = -EIO;
499                 CHSC_MSG(0, "sscud: response code=%x\n",
500                          sscud_area->response.code);
501                 goto out_free;
502         }
503         memcpy(&cud->scub, &sscud_area->response, sscud_area->response.length);
504         if (copy_to_user(user_cud, cud, sizeof(*cud)))
505                 ret = -EFAULT;
506         else
507                 ret = 0;
508 out_free:
509         kfree(cud);
510         free_page((unsigned long)sscud_area);
511         return ret;
512 }
513
514 static int chsc_ioctl_conf_info(void __user *user_ci)
515 {
516         struct chsc_conf_info *ci;
517         int ret, ccode;
518         struct {
519                 struct chsc_header request;
520                 u32 : 2;
521                 u32 m : 1;
522                 u32 : 1;
523                 u32 fmt1 : 4;
524                 u32 cssid : 8;
525                 u32 : 6;
526                 u32 ssid : 2;
527                 u32 : 8;
528                 u64 : 64;
529                 struct chsc_header response;
530                 u8 data[PAGE_SIZE - 20];
531         } __attribute__ ((packed)) *sci_area;
532
533         sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
534         if (!sci_area)
535                 return -ENOMEM;
536         ci = kzalloc(sizeof(*ci), GFP_KERNEL);
537         if (!ci) {
538                 ret = -ENOMEM;
539                 goto out_free;
540         }
541         if (copy_from_user(ci, user_ci, sizeof(*ci))) {
542                 ret = -EFAULT;
543                 goto out_free;
544         }
545         sci_area->request.length = 0x0010;
546         sci_area->request.code = 0x0012;
547         sci_area->m = ci->id.m;
548         sci_area->fmt1 = ci->fmt;
549         sci_area->cssid = ci->id.cssid;
550         sci_area->ssid = ci->id.ssid;
551
552         ccode = chsc(sci_area);
553         if (ccode != 0) {
554                 ret = -EIO;
555                 goto out_free;
556         }
557         if (sci_area->response.code != 0x0001) {
558                 ret = -EIO;
559                 CHSC_MSG(0, "sci: response code=%x\n",
560                          sci_area->response.code);
561                 goto out_free;
562         }
563         memcpy(&ci->scid, &sci_area->response, sci_area->response.length);
564         if (copy_to_user(user_ci, ci, sizeof(*ci)))
565                 ret = -EFAULT;
566         else
567                 ret = 0;
568 out_free:
569         kfree(ci);
570         free_page((unsigned long)sci_area);
571         return ret;
572 }
573
574 static int chsc_ioctl_conf_comp_list(void __user *user_ccl)
575 {
576         struct chsc_comp_list *ccl;
577         int ret, ccode;
578         struct {
579                 struct chsc_header request;
580                 u32 ctype : 8;
581                 u32 : 4;
582                 u32 fmt : 4;
583                 u32 : 16;
584                 u64 : 64;
585                 u32 list_parm[2];
586                 u64 : 64;
587                 struct chsc_header response;
588                 u8 data[PAGE_SIZE - 36];
589         } __attribute__ ((packed)) *sccl_area;
590         struct {
591                 u32 m : 1;
592                 u32 : 31;
593                 u32 cssid : 8;
594                 u32 : 16;
595                 u32 chpid : 8;
596         } __attribute__ ((packed)) *chpid_parm;
597         struct {
598                 u32 f_cssid : 8;
599                 u32 l_cssid : 8;
600                 u32 : 16;
601                 u32 res;
602         } __attribute__ ((packed)) *cssids_parm;
603
604         sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
605         if (!sccl_area)
606                 return -ENOMEM;
607         ccl = kzalloc(sizeof(*ccl), GFP_KERNEL);
608         if (!ccl) {
609                 ret = -ENOMEM;
610                 goto out_free;
611         }
612         if (copy_from_user(ccl, user_ccl, sizeof(*ccl))) {
613                 ret = -EFAULT;
614                 goto out_free;
615         }
616         sccl_area->request.length = 0x0020;
617         sccl_area->request.code = 0x0030;
618         sccl_area->fmt = ccl->req.fmt;
619         sccl_area->ctype = ccl->req.ctype;
620         switch (sccl_area->ctype) {
621         case CCL_CU_ON_CHP:
622         case CCL_IOP_CHP:
623                 chpid_parm = (void *)&sccl_area->list_parm;
624                 chpid_parm->m = ccl->req.chpid.m;
625                 chpid_parm->cssid = ccl->req.chpid.chp.cssid;
626                 chpid_parm->chpid = ccl->req.chpid.chp.id;
627                 break;
628         case CCL_CSS_IMG:
629         case CCL_CSS_IMG_CONF_CHAR:
630                 cssids_parm = (void *)&sccl_area->list_parm;
631                 cssids_parm->f_cssid = ccl->req.cssids.f_cssid;
632                 cssids_parm->l_cssid = ccl->req.cssids.l_cssid;
633                 break;
634         }
635         ccode = chsc(sccl_area);
636         if (ccode != 0) {
637                 ret = -EIO;
638                 goto out_free;
639         }
640         if (sccl_area->response.code != 0x0001) {
641                 ret = -EIO;
642                 CHSC_MSG(0, "sccl: response code=%x\n",
643                          sccl_area->response.code);
644                 goto out_free;
645         }
646         memcpy(&ccl->sccl, &sccl_area->response, sccl_area->response.length);
647         if (copy_to_user(user_ccl, ccl, sizeof(*ccl)))
648                 ret = -EFAULT;
649         else
650                 ret = 0;
651 out_free:
652         kfree(ccl);
653         free_page((unsigned long)sccl_area);
654         return ret;
655 }
656
657 static int chsc_ioctl_chpd(void __user *user_chpd)
658 {
659         struct chsc_cpd_info *chpd;
660         int ret;
661
662         chpd = kzalloc(sizeof(*chpd), GFP_KERNEL);
663         if (!chpd)
664                 return -ENOMEM;
665         if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) {
666                 ret = -EFAULT;
667                 goto out_free;
668         }
669         ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt,
670                                                chpd->rfmt, chpd->c, chpd->m,
671                                                &chpd->chpdb);
672         if (ret)
673                 goto out_free;
674         if (copy_to_user(user_chpd, chpd, sizeof(*chpd)))
675                 ret = -EFAULT;
676 out_free:
677         kfree(chpd);
678         return ret;
679 }
680
681 static int chsc_ioctl_dcal(void __user *user_dcal)
682 {
683         struct chsc_dcal *dcal;
684         int ret, ccode;
685         struct {
686                 struct chsc_header request;
687                 u32 atype : 8;
688                 u32 : 4;
689                 u32 fmt : 4;
690                 u32 : 16;
691                 u32 res0[2];
692                 u32 list_parm[2];
693                 u32 res1[2];
694                 struct chsc_header response;
695                 u8 data[PAGE_SIZE - 36];
696         } __attribute__ ((packed)) *sdcal_area;
697
698         sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
699         if (!sdcal_area)
700                 return -ENOMEM;
701         dcal = kzalloc(sizeof(*dcal), GFP_KERNEL);
702         if (!dcal) {
703                 ret = -ENOMEM;
704                 goto out_free;
705         }
706         if (copy_from_user(dcal, user_dcal, sizeof(*dcal))) {
707                 ret = -EFAULT;
708                 goto out_free;
709         }
710         sdcal_area->request.length = 0x0020;
711         sdcal_area->request.code = 0x0034;
712         sdcal_area->atype = dcal->req.atype;
713         sdcal_area->fmt = dcal->req.fmt;
714         memcpy(&sdcal_area->list_parm, &dcal->req.list_parm,
715                sizeof(sdcal_area->list_parm));
716
717         ccode = chsc(sdcal_area);
718         if (ccode != 0) {
719                 ret = -EIO;
720                 goto out_free;
721         }
722         if (sdcal_area->response.code != 0x0001) {
723                 ret = -EIO;
724                 CHSC_MSG(0, "sdcal: response code=%x\n",
725                          sdcal_area->response.code);
726                 goto out_free;
727         }
728         memcpy(&dcal->sdcal, &sdcal_area->response,
729                sdcal_area->response.length);
730         if (copy_to_user(user_dcal, dcal, sizeof(*dcal)))
731                 ret = -EFAULT;
732         else
733                 ret = 0;
734 out_free:
735         kfree(dcal);
736         free_page((unsigned long)sdcal_area);
737         return ret;
738 }
739
740 static long chsc_ioctl(struct file *filp, unsigned int cmd,
741                        unsigned long arg)
742 {
743         CHSC_MSG(2, "chsc_ioctl called, cmd=%x\n", cmd);
744         switch (cmd) {
745         case CHSC_START:
746                 return chsc_ioctl_start((void __user *)arg);
747         case CHSC_INFO_CHANNEL_PATH:
748                 return chsc_ioctl_info_channel_path((void __user *)arg);
749         case CHSC_INFO_CU:
750                 return chsc_ioctl_info_cu((void __user *)arg);
751         case CHSC_INFO_SCH_CU:
752                 return chsc_ioctl_info_sch_cu((void __user *)arg);
753         case CHSC_INFO_CI:
754                 return chsc_ioctl_conf_info((void __user *)arg);
755         case CHSC_INFO_CCL:
756                 return chsc_ioctl_conf_comp_list((void __user *)arg);
757         case CHSC_INFO_CPD:
758                 return chsc_ioctl_chpd((void __user *)arg);
759         case CHSC_INFO_DCAL:
760                 return chsc_ioctl_dcal((void __user *)arg);
761         default: /* unknown ioctl number */
762                 return -ENOIOCTLCMD;
763         }
764 }
765
766 static const struct file_operations chsc_fops = {
767         .owner = THIS_MODULE,
768         .unlocked_ioctl = chsc_ioctl,
769         .compat_ioctl = chsc_ioctl,
770 };
771
772 static struct miscdevice chsc_misc_device = {
773         .minor = MISC_DYNAMIC_MINOR,
774         .name = "chsc",
775         .fops = &chsc_fops,
776 };
777
778 static int __init chsc_misc_init(void)
779 {
780         return misc_register(&chsc_misc_device);
781 }
782
783 static void chsc_misc_cleanup(void)
784 {
785         misc_deregister(&chsc_misc_device);
786 }
787
788 static int __init chsc_sch_init(void)
789 {
790         int ret;
791
792         ret = chsc_init_dbfs();
793         if (ret)
794                 return ret;
795         isc_register(CHSC_SCH_ISC);
796         ret = chsc_init_sch_driver();
797         if (ret)
798                 goto out_dbf;
799         ret = chsc_misc_init();
800         if (ret)
801                 goto out_driver;
802         return ret;
803 out_driver:
804         chsc_cleanup_sch_driver();
805 out_dbf:
806         isc_unregister(CHSC_SCH_ISC);
807         chsc_remove_dbfs();
808         return ret;
809 }
810
811 static void __exit chsc_sch_exit(void)
812 {
813         chsc_misc_cleanup();
814         chsc_cleanup_sch_driver();
815         isc_unregister(CHSC_SCH_ISC);
816         chsc_remove_dbfs();
817 }
818
819 module_init(chsc_sch_init);
820 module_exit(chsc_sch_exit);