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