0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 #include <linux/module.h>
0075 #include <linux/kernel.h>
0076 #include <linux/types.h>
0077 #include <linux/ioport.h>
0078 #include <linux/interrupt.h>
0079 #include <linux/fcntl.h>
0080 #include <linux/init.h>
0081 #include <linux/poll.h>
0082 #include <linux/proc_fs.h>
0083 #include <linux/mutex.h>
0084 #include <linux/sysctl.h>
0085 #include <linux/fs.h>
0086 #include <linux/cdev.h>
0087 #include <linux/platform_device.h>
0088 #include <linux/slab.h>
0089 #include <linux/io.h>
0090 #include <linux/uaccess.h>
0091
0092 #ifdef CONFIG_OF
0093
0094 #include <linux/of_address.h>
0095 #include <linux/of_device.h>
0096 #include <linux/of_platform.h>
0097 #endif
0098
0099 #include "xilinx_hwicap.h"
0100 #include "buffer_icap.h"
0101 #include "fifo_icap.h"
0102
0103 #define DRIVER_NAME "icap"
0104
0105 #define HWICAP_REGS (0x10000)
0106
0107 #define XHWICAP_MAJOR 259
0108 #define XHWICAP_MINOR 0
0109 #define HWICAP_DEVICES 1
0110
0111
0112 static DEFINE_MUTEX(hwicap_mutex);
0113 static bool probed_devices[HWICAP_DEVICES];
0114 static struct mutex icap_sem;
0115
0116 static struct class *icap_class;
0117
0118 #define UNIMPLEMENTED 0xFFFF
0119
0120 static const struct config_registers v2_config_registers = {
0121 .CRC = 0,
0122 .FAR = 1,
0123 .FDRI = 2,
0124 .FDRO = 3,
0125 .CMD = 4,
0126 .CTL = 5,
0127 .MASK = 6,
0128 .STAT = 7,
0129 .LOUT = 8,
0130 .COR = 9,
0131 .MFWR = 10,
0132 .FLR = 11,
0133 .KEY = 12,
0134 .CBC = 13,
0135 .IDCODE = 14,
0136 .AXSS = UNIMPLEMENTED,
0137 .C0R_1 = UNIMPLEMENTED,
0138 .CSOB = UNIMPLEMENTED,
0139 .WBSTAR = UNIMPLEMENTED,
0140 .TIMER = UNIMPLEMENTED,
0141 .BOOTSTS = UNIMPLEMENTED,
0142 .CTL_1 = UNIMPLEMENTED,
0143 };
0144
0145 static const struct config_registers v4_config_registers = {
0146 .CRC = 0,
0147 .FAR = 1,
0148 .FDRI = 2,
0149 .FDRO = 3,
0150 .CMD = 4,
0151 .CTL = 5,
0152 .MASK = 6,
0153 .STAT = 7,
0154 .LOUT = 8,
0155 .COR = 9,
0156 .MFWR = 10,
0157 .FLR = UNIMPLEMENTED,
0158 .KEY = UNIMPLEMENTED,
0159 .CBC = 11,
0160 .IDCODE = 12,
0161 .AXSS = 13,
0162 .C0R_1 = UNIMPLEMENTED,
0163 .CSOB = UNIMPLEMENTED,
0164 .WBSTAR = UNIMPLEMENTED,
0165 .TIMER = UNIMPLEMENTED,
0166 .BOOTSTS = UNIMPLEMENTED,
0167 .CTL_1 = UNIMPLEMENTED,
0168 };
0169
0170 static const struct config_registers v5_config_registers = {
0171 .CRC = 0,
0172 .FAR = 1,
0173 .FDRI = 2,
0174 .FDRO = 3,
0175 .CMD = 4,
0176 .CTL = 5,
0177 .MASK = 6,
0178 .STAT = 7,
0179 .LOUT = 8,
0180 .COR = 9,
0181 .MFWR = 10,
0182 .FLR = UNIMPLEMENTED,
0183 .KEY = UNIMPLEMENTED,
0184 .CBC = 11,
0185 .IDCODE = 12,
0186 .AXSS = 13,
0187 .C0R_1 = 14,
0188 .CSOB = 15,
0189 .WBSTAR = 16,
0190 .TIMER = 17,
0191 .BOOTSTS = 18,
0192 .CTL_1 = 19,
0193 };
0194
0195 static const struct config_registers v6_config_registers = {
0196 .CRC = 0,
0197 .FAR = 1,
0198 .FDRI = 2,
0199 .FDRO = 3,
0200 .CMD = 4,
0201 .CTL = 5,
0202 .MASK = 6,
0203 .STAT = 7,
0204 .LOUT = 8,
0205 .COR = 9,
0206 .MFWR = 10,
0207 .FLR = UNIMPLEMENTED,
0208 .KEY = UNIMPLEMENTED,
0209 .CBC = 11,
0210 .IDCODE = 12,
0211 .AXSS = 13,
0212 .C0R_1 = 14,
0213 .CSOB = 15,
0214 .WBSTAR = 16,
0215 .TIMER = 17,
0216 .BOOTSTS = 22,
0217 .CTL_1 = 24,
0218 };
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 static int hwicap_command_desync(struct hwicap_drvdata *drvdata)
0231 {
0232 u32 buffer[4];
0233 u32 index = 0;
0234
0235
0236
0237
0238 buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
0239 buffer[index++] = XHI_CMD_DESYNCH;
0240 buffer[index++] = XHI_NOOP_PACKET;
0241 buffer[index++] = XHI_NOOP_PACKET;
0242
0243
0244
0245
0246
0247 return drvdata->config->set_configuration(drvdata,
0248 &buffer[0], index);
0249 }
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264 static int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
0265 u32 reg, u32 *reg_data)
0266 {
0267 int status;
0268 u32 buffer[6];
0269 u32 index = 0;
0270
0271
0272
0273
0274 buffer[index++] = XHI_DUMMY_PACKET;
0275 buffer[index++] = XHI_NOOP_PACKET;
0276 buffer[index++] = XHI_SYNC_PACKET;
0277 buffer[index++] = XHI_NOOP_PACKET;
0278 buffer[index++] = XHI_NOOP_PACKET;
0279
0280
0281
0282
0283
0284 status = drvdata->config->set_configuration(drvdata,
0285 &buffer[0], index);
0286 if (status)
0287 return status;
0288
0289
0290 status = drvdata->config->get_status(drvdata);
0291 if ((status & XHI_SR_DALIGN_MASK) != XHI_SR_DALIGN_MASK)
0292 return -EIO;
0293
0294 index = 0;
0295 buffer[index++] = hwicap_type_1_read(reg) | 1;
0296 buffer[index++] = XHI_NOOP_PACKET;
0297 buffer[index++] = XHI_NOOP_PACKET;
0298
0299
0300
0301
0302
0303 status = drvdata->config->set_configuration(drvdata,
0304 &buffer[0], index);
0305 if (status)
0306 return status;
0307
0308
0309
0310
0311 status = drvdata->config->get_configuration(drvdata, reg_data, 1);
0312 if (status)
0313 return status;
0314
0315 return 0;
0316 }
0317
0318 static int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
0319 {
0320 int status;
0321 u32 idcode;
0322
0323 dev_dbg(drvdata->dev, "initializing\n");
0324
0325
0326
0327
0328 dev_dbg(drvdata->dev, "Reset...\n");
0329 drvdata->config->reset(drvdata);
0330
0331 dev_dbg(drvdata->dev, "Desync...\n");
0332 status = hwicap_command_desync(drvdata);
0333 if (status)
0334 return status;
0335
0336
0337
0338
0339
0340 dev_dbg(drvdata->dev, "Reading IDCODE...\n");
0341 status = hwicap_get_configuration_register(
0342 drvdata, drvdata->config_regs->IDCODE, &idcode);
0343 dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode);
0344 if (status)
0345 return status;
0346
0347 dev_dbg(drvdata->dev, "Desync...\n");
0348 status = hwicap_command_desync(drvdata);
0349 if (status)
0350 return status;
0351
0352 return 0;
0353 }
0354
0355 static ssize_t
0356 hwicap_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
0357 {
0358 struct hwicap_drvdata *drvdata = file->private_data;
0359 ssize_t bytes_to_read = 0;
0360 u32 *kbuf;
0361 u32 words;
0362 u32 bytes_remaining;
0363 int status;
0364
0365 status = mutex_lock_interruptible(&drvdata->sem);
0366 if (status)
0367 return status;
0368
0369 if (drvdata->read_buffer_in_use) {
0370
0371
0372
0373 bytes_to_read =
0374 (count < drvdata->read_buffer_in_use) ? count :
0375 drvdata->read_buffer_in_use;
0376
0377
0378 if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) {
0379 status = -EFAULT;
0380 goto error;
0381 }
0382 drvdata->read_buffer_in_use -= bytes_to_read;
0383 memmove(drvdata->read_buffer,
0384 drvdata->read_buffer + bytes_to_read,
0385 4 - bytes_to_read);
0386 } else {
0387
0388 kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
0389 if (!kbuf) {
0390 status = -ENOMEM;
0391 goto error;
0392 }
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402 words = ((count + 3) >> 2);
0403 bytes_to_read = words << 2;
0404
0405 if (bytes_to_read > PAGE_SIZE)
0406 bytes_to_read = PAGE_SIZE;
0407
0408
0409 bytes_remaining = bytes_to_read & 3;
0410 bytes_to_read &= ~3;
0411 words = bytes_to_read >> 2;
0412
0413 status = drvdata->config->get_configuration(drvdata,
0414 kbuf, words);
0415
0416
0417 if (status) {
0418 free_page((unsigned long)kbuf);
0419 goto error;
0420 }
0421
0422
0423 if (copy_to_user(buf, kbuf, bytes_to_read)) {
0424 free_page((unsigned long)kbuf);
0425 status = -EFAULT;
0426 goto error;
0427 }
0428 memcpy(drvdata->read_buffer,
0429 kbuf,
0430 bytes_remaining);
0431 drvdata->read_buffer_in_use = bytes_remaining;
0432 free_page((unsigned long)kbuf);
0433 }
0434 status = bytes_to_read;
0435 error:
0436 mutex_unlock(&drvdata->sem);
0437 return status;
0438 }
0439
0440 static ssize_t
0441 hwicap_write(struct file *file, const char __user *buf,
0442 size_t count, loff_t *ppos)
0443 {
0444 struct hwicap_drvdata *drvdata = file->private_data;
0445 ssize_t written = 0;
0446 ssize_t left = count;
0447 u32 *kbuf;
0448 ssize_t len;
0449 ssize_t status;
0450
0451 status = mutex_lock_interruptible(&drvdata->sem);
0452 if (status)
0453 return status;
0454
0455 left += drvdata->write_buffer_in_use;
0456
0457
0458 if (left < 4) {
0459 status = 0;
0460 goto error;
0461 }
0462
0463 kbuf = (u32 *) __get_free_page(GFP_KERNEL);
0464 if (!kbuf) {
0465 status = -ENOMEM;
0466 goto error;
0467 }
0468
0469 while (left > 3) {
0470
0471
0472 len = left;
0473
0474 if (len > PAGE_SIZE)
0475 len = PAGE_SIZE;
0476 len &= ~3;
0477
0478 if (drvdata->write_buffer_in_use) {
0479 memcpy(kbuf, drvdata->write_buffer,
0480 drvdata->write_buffer_in_use);
0481 if (copy_from_user(
0482 (((char *)kbuf) + drvdata->write_buffer_in_use),
0483 buf + written,
0484 len - (drvdata->write_buffer_in_use))) {
0485 free_page((unsigned long)kbuf);
0486 status = -EFAULT;
0487 goto error;
0488 }
0489 } else {
0490 if (copy_from_user(kbuf, buf + written, len)) {
0491 free_page((unsigned long)kbuf);
0492 status = -EFAULT;
0493 goto error;
0494 }
0495 }
0496
0497 status = drvdata->config->set_configuration(drvdata,
0498 kbuf, len >> 2);
0499
0500 if (status) {
0501 free_page((unsigned long)kbuf);
0502 status = -EFAULT;
0503 goto error;
0504 }
0505 if (drvdata->write_buffer_in_use) {
0506 len -= drvdata->write_buffer_in_use;
0507 left -= drvdata->write_buffer_in_use;
0508 drvdata->write_buffer_in_use = 0;
0509 }
0510 written += len;
0511 left -= len;
0512 }
0513 if ((left > 0) && (left < 4)) {
0514 if (!copy_from_user(drvdata->write_buffer,
0515 buf + written, left)) {
0516 drvdata->write_buffer_in_use = left;
0517 written += left;
0518 left = 0;
0519 }
0520 }
0521
0522 free_page((unsigned long)kbuf);
0523 status = written;
0524 error:
0525 mutex_unlock(&drvdata->sem);
0526 return status;
0527 }
0528
0529 static int hwicap_open(struct inode *inode, struct file *file)
0530 {
0531 struct hwicap_drvdata *drvdata;
0532 int status;
0533
0534 mutex_lock(&hwicap_mutex);
0535 drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
0536
0537 status = mutex_lock_interruptible(&drvdata->sem);
0538 if (status)
0539 goto out;
0540
0541 if (drvdata->is_open) {
0542 status = -EBUSY;
0543 goto error;
0544 }
0545
0546 status = hwicap_initialize_hwicap(drvdata);
0547 if (status) {
0548 dev_err(drvdata->dev, "Failed to open file");
0549 goto error;
0550 }
0551
0552 file->private_data = drvdata;
0553 drvdata->write_buffer_in_use = 0;
0554 drvdata->read_buffer_in_use = 0;
0555 drvdata->is_open = 1;
0556
0557 error:
0558 mutex_unlock(&drvdata->sem);
0559 out:
0560 mutex_unlock(&hwicap_mutex);
0561 return status;
0562 }
0563
0564 static int hwicap_release(struct inode *inode, struct file *file)
0565 {
0566 struct hwicap_drvdata *drvdata = file->private_data;
0567 int i;
0568 int status = 0;
0569
0570 mutex_lock(&drvdata->sem);
0571
0572 if (drvdata->write_buffer_in_use) {
0573
0574 for (i = drvdata->write_buffer_in_use; i < 4; i++)
0575 drvdata->write_buffer[i] = 0;
0576
0577 status = drvdata->config->set_configuration(drvdata,
0578 (u32 *) drvdata->write_buffer, 1);
0579 if (status)
0580 goto error;
0581 }
0582
0583 status = hwicap_command_desync(drvdata);
0584 if (status)
0585 goto error;
0586
0587 error:
0588 drvdata->is_open = 0;
0589 mutex_unlock(&drvdata->sem);
0590 return status;
0591 }
0592
0593 static const struct file_operations hwicap_fops = {
0594 .owner = THIS_MODULE,
0595 .write = hwicap_write,
0596 .read = hwicap_read,
0597 .open = hwicap_open,
0598 .release = hwicap_release,
0599 .llseek = noop_llseek,
0600 };
0601
0602 static int hwicap_setup(struct device *dev, int id,
0603 const struct resource *regs_res,
0604 const struct hwicap_driver_config *config,
0605 const struct config_registers *config_regs)
0606 {
0607 dev_t devt;
0608 struct hwicap_drvdata *drvdata = NULL;
0609 int retval = 0;
0610
0611 dev_info(dev, "Xilinx icap port driver\n");
0612
0613 mutex_lock(&icap_sem);
0614
0615 if (id < 0) {
0616 for (id = 0; id < HWICAP_DEVICES; id++)
0617 if (!probed_devices[id])
0618 break;
0619 }
0620 if (id < 0 || id >= HWICAP_DEVICES) {
0621 mutex_unlock(&icap_sem);
0622 dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);
0623 return -EINVAL;
0624 }
0625 if (probed_devices[id]) {
0626 mutex_unlock(&icap_sem);
0627 dev_err(dev, "cannot assign to %s%i; it is already in use\n",
0628 DRIVER_NAME, id);
0629 return -EBUSY;
0630 }
0631
0632 probed_devices[id] = 1;
0633 mutex_unlock(&icap_sem);
0634
0635 devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR + id);
0636
0637 drvdata = kzalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
0638 if (!drvdata) {
0639 retval = -ENOMEM;
0640 goto failed0;
0641 }
0642 dev_set_drvdata(dev, (void *)drvdata);
0643
0644 if (!regs_res) {
0645 dev_err(dev, "Couldn't get registers resource\n");
0646 retval = -EFAULT;
0647 goto failed1;
0648 }
0649
0650 drvdata->mem_start = regs_res->start;
0651 drvdata->mem_end = regs_res->end;
0652 drvdata->mem_size = resource_size(regs_res);
0653
0654 if (!request_mem_region(drvdata->mem_start,
0655 drvdata->mem_size, DRIVER_NAME)) {
0656 dev_err(dev, "Couldn't lock memory region at %Lx\n",
0657 (unsigned long long) regs_res->start);
0658 retval = -EBUSY;
0659 goto failed1;
0660 }
0661
0662 drvdata->devt = devt;
0663 drvdata->dev = dev;
0664 drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size);
0665 if (!drvdata->base_address) {
0666 dev_err(dev, "ioremap() failed\n");
0667 retval = -ENOMEM;
0668 goto failed2;
0669 }
0670
0671 drvdata->config = config;
0672 drvdata->config_regs = config_regs;
0673
0674 mutex_init(&drvdata->sem);
0675 drvdata->is_open = 0;
0676
0677 dev_info(dev, "ioremap %llx to %p with size %llx\n",
0678 (unsigned long long) drvdata->mem_start,
0679 drvdata->base_address,
0680 (unsigned long long) drvdata->mem_size);
0681
0682 cdev_init(&drvdata->cdev, &hwicap_fops);
0683 drvdata->cdev.owner = THIS_MODULE;
0684 retval = cdev_add(&drvdata->cdev, devt, 1);
0685 if (retval) {
0686 dev_err(dev, "cdev_add() failed\n");
0687 goto failed3;
0688 }
0689
0690 device_create(icap_class, dev, devt, NULL, "%s%d", DRIVER_NAME, id);
0691 return 0;
0692
0693 failed3:
0694 iounmap(drvdata->base_address);
0695
0696 failed2:
0697 release_mem_region(regs_res->start, drvdata->mem_size);
0698
0699 failed1:
0700 kfree(drvdata);
0701
0702 failed0:
0703 mutex_lock(&icap_sem);
0704 probed_devices[id] = 0;
0705 mutex_unlock(&icap_sem);
0706
0707 return retval;
0708 }
0709
0710 static struct hwicap_driver_config buffer_icap_config = {
0711 .get_configuration = buffer_icap_get_configuration,
0712 .set_configuration = buffer_icap_set_configuration,
0713 .get_status = buffer_icap_get_status,
0714 .reset = buffer_icap_reset,
0715 };
0716
0717 static struct hwicap_driver_config fifo_icap_config = {
0718 .get_configuration = fifo_icap_get_configuration,
0719 .set_configuration = fifo_icap_set_configuration,
0720 .get_status = fifo_icap_get_status,
0721 .reset = fifo_icap_reset,
0722 };
0723
0724 static int hwicap_remove(struct device *dev)
0725 {
0726 struct hwicap_drvdata *drvdata;
0727
0728 drvdata = dev_get_drvdata(dev);
0729
0730 if (!drvdata)
0731 return 0;
0732
0733 device_destroy(icap_class, drvdata->devt);
0734 cdev_del(&drvdata->cdev);
0735 iounmap(drvdata->base_address);
0736 release_mem_region(drvdata->mem_start, drvdata->mem_size);
0737 kfree(drvdata);
0738
0739 mutex_lock(&icap_sem);
0740 probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0;
0741 mutex_unlock(&icap_sem);
0742 return 0;
0743 }
0744
0745 #ifdef CONFIG_OF
0746 static int hwicap_of_probe(struct platform_device *op,
0747 const struct hwicap_driver_config *config)
0748 {
0749 struct resource res;
0750 const unsigned int *id;
0751 const char *family;
0752 int rc;
0753 const struct config_registers *regs;
0754
0755
0756 rc = of_address_to_resource(op->dev.of_node, 0, &res);
0757 if (rc) {
0758 dev_err(&op->dev, "invalid address\n");
0759 return rc;
0760 }
0761
0762 id = of_get_property(op->dev.of_node, "port-number", NULL);
0763
0764
0765
0766
0767 regs = &v4_config_registers;
0768 family = of_get_property(op->dev.of_node, "xlnx,family", NULL);
0769
0770 if (family) {
0771 if (!strcmp(family, "virtex2p"))
0772 regs = &v2_config_registers;
0773 else if (!strcmp(family, "virtex4"))
0774 regs = &v4_config_registers;
0775 else if (!strcmp(family, "virtex5"))
0776 regs = &v5_config_registers;
0777 else if (!strcmp(family, "virtex6"))
0778 regs = &v6_config_registers;
0779 }
0780 return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
0781 regs);
0782 }
0783 #else
0784 static inline int hwicap_of_probe(struct platform_device *op,
0785 const struct hwicap_driver_config *config)
0786 {
0787 return -EINVAL;
0788 }
0789 #endif
0790
0791 static const struct of_device_id hwicap_of_match[];
0792 static int hwicap_drv_probe(struct platform_device *pdev)
0793 {
0794 const struct of_device_id *match;
0795 struct resource *res;
0796 const struct config_registers *regs;
0797 const char *family;
0798
0799 match = of_match_device(hwicap_of_match, &pdev->dev);
0800 if (match)
0801 return hwicap_of_probe(pdev, match->data);
0802
0803 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0804 if (!res)
0805 return -ENODEV;
0806
0807
0808
0809
0810 regs = &v4_config_registers;
0811 family = pdev->dev.platform_data;
0812
0813 if (family) {
0814 if (!strcmp(family, "virtex2p"))
0815 regs = &v2_config_registers;
0816 else if (!strcmp(family, "virtex4"))
0817 regs = &v4_config_registers;
0818 else if (!strcmp(family, "virtex5"))
0819 regs = &v5_config_registers;
0820 else if (!strcmp(family, "virtex6"))
0821 regs = &v6_config_registers;
0822 }
0823
0824 return hwicap_setup(&pdev->dev, pdev->id, res,
0825 &buffer_icap_config, regs);
0826 }
0827
0828 static int hwicap_drv_remove(struct platform_device *pdev)
0829 {
0830 return hwicap_remove(&pdev->dev);
0831 }
0832
0833 #ifdef CONFIG_OF
0834
0835 static const struct of_device_id hwicap_of_match[] = {
0836 { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},
0837 { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config},
0838 {},
0839 };
0840 MODULE_DEVICE_TABLE(of, hwicap_of_match);
0841 #else
0842 #define hwicap_of_match NULL
0843 #endif
0844
0845 static struct platform_driver hwicap_platform_driver = {
0846 .probe = hwicap_drv_probe,
0847 .remove = hwicap_drv_remove,
0848 .driver = {
0849 .name = DRIVER_NAME,
0850 .of_match_table = hwicap_of_match,
0851 },
0852 };
0853
0854 static int __init hwicap_module_init(void)
0855 {
0856 dev_t devt;
0857 int retval;
0858
0859 icap_class = class_create(THIS_MODULE, "xilinx_config");
0860 mutex_init(&icap_sem);
0861
0862 devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR);
0863 retval = register_chrdev_region(devt,
0864 HWICAP_DEVICES,
0865 DRIVER_NAME);
0866 if (retval < 0)
0867 return retval;
0868
0869 retval = platform_driver_register(&hwicap_platform_driver);
0870 if (retval)
0871 goto failed;
0872
0873 return retval;
0874
0875 failed:
0876 unregister_chrdev_region(devt, HWICAP_DEVICES);
0877
0878 return retval;
0879 }
0880
0881 static void __exit hwicap_module_cleanup(void)
0882 {
0883 dev_t devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR);
0884
0885 class_destroy(icap_class);
0886
0887 platform_driver_unregister(&hwicap_platform_driver);
0888
0889 unregister_chrdev_region(devt, HWICAP_DEVICES);
0890 }
0891
0892 module_init(hwicap_module_init);
0893 module_exit(hwicap_module_cleanup);
0894
0895 MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group");
0896 MODULE_DESCRIPTION("Xilinx ICAP Port Driver");
0897 MODULE_LICENSE("GPL");