2005-04-17 02:20:36 +04:00
/*
* ( C ) Copyright IBM Corp . 2004
2006-02-01 14:06:31 +03:00
* tape_class . c
2005-04-17 02:20:36 +04:00
*
* Tape class device support
*
* Author : Stefan Bader < shbader @ de . ibm . com >
* Based on simple class device code by Greg K - H
*/
# include "tape_class.h"
MODULE_AUTHOR ( " Stefan Bader <shbader@de.ibm.com> " ) ;
MODULE_DESCRIPTION (
" (C) Copyright IBM Corp. 2004 All Rights Reserved. \n "
2006-02-01 14:06:31 +03:00
" tape_class.c "
2005-04-17 02:20:36 +04:00
) ;
MODULE_LICENSE ( " GPL " ) ;
2005-03-23 21:01:41 +03:00
static struct class * tape_class ;
2005-04-17 02:20:36 +04:00
/*
* Register a tape device and return a pointer to the cdev structure .
*
* device
* The pointer to the struct device of the physical ( base ) device .
* drivername
* The pointer to the drivers name for it ' s character devices .
* dev
* The intended major / minor number . The major number may be 0 to
* get a dynamic major number .
* fops
* The pointer to the drivers file operations for the tape device .
* devname
* The pointer to the name of the character device .
*/
struct tape_class_device * register_tape_dev (
struct device * device ,
dev_t dev ,
2007-02-12 11:55:37 +03:00
const struct file_operations * fops ,
2005-04-17 02:20:36 +04:00
char * device_name ,
char * mode_name )
{
struct tape_class_device * tcd ;
int rc ;
char * s ;
2006-03-24 14:15:31 +03:00
tcd = kzalloc ( sizeof ( struct tape_class_device ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! tcd )
return ERR_PTR ( - ENOMEM ) ;
strncpy ( tcd - > device_name , device_name , TAPECLASS_NAME_LEN ) ;
for ( s = strchr ( tcd - > device_name , ' / ' ) ; s ; s = strchr ( s , ' / ' ) )
* s = ' ! ' ;
strncpy ( tcd - > mode_name , mode_name , TAPECLASS_NAME_LEN ) ;
for ( s = strchr ( tcd - > mode_name , ' / ' ) ; s ; s = strchr ( s , ' / ' ) )
* s = ' ! ' ;
tcd - > char_device = cdev_alloc ( ) ;
if ( ! tcd - > char_device ) {
rc = - ENOMEM ;
goto fail_with_tcd ;
}
tcd - > char_device - > owner = fops - > owner ;
tcd - > char_device - > ops = fops ;
tcd - > char_device - > dev = dev ;
rc = cdev_add ( tcd - > char_device , tcd - > char_device - > dev , 1 ) ;
if ( rc )
goto fail_with_cdev ;
2005-03-23 21:01:41 +03:00
tcd - > class_device = class_device_create (
2005-04-17 02:20:36 +04:00
tape_class ,
2005-10-28 09:25:43 +04:00
NULL ,
2005-04-17 02:20:36 +04:00
tcd - > char_device - > dev ,
device ,
" %s " , tcd - > device_name
) ;
2006-08-07 19:00:28 +04:00
rc = IS_ERR ( tcd - > class_device ) ? PTR_ERR ( tcd - > class_device ) : 0 ;
2006-07-18 15:46:58 +04:00
if ( rc )
goto fail_with_cdev ;
rc = sysfs_create_link (
2005-04-17 02:20:36 +04:00
& device - > kobj ,
& tcd - > class_device - > kobj ,
tcd - > mode_name
) ;
2006-07-18 15:46:58 +04:00
if ( rc )
goto fail_with_class_device ;
2005-04-17 02:20:36 +04:00
return tcd ;
2006-07-18 15:46:58 +04:00
fail_with_class_device :
class_device_destroy ( tape_class , tcd - > char_device - > dev ) ;
2005-04-17 02:20:36 +04:00
fail_with_cdev :
cdev_del ( tcd - > char_device ) ;
fail_with_tcd :
kfree ( tcd ) ;
return ERR_PTR ( rc ) ;
}
EXPORT_SYMBOL ( register_tape_dev ) ;
void unregister_tape_dev ( struct tape_class_device * tcd )
{
if ( tcd ! = NULL & & ! IS_ERR ( tcd ) ) {
sysfs_remove_link (
& tcd - > class_device - > dev - > kobj ,
tcd - > mode_name
) ;
2005-03-23 21:01:41 +03:00
class_device_destroy ( tape_class , tcd - > char_device - > dev ) ;
2005-04-17 02:20:36 +04:00
cdev_del ( tcd - > char_device ) ;
kfree ( tcd ) ;
}
}
EXPORT_SYMBOL ( unregister_tape_dev ) ;
static int __init tape_init ( void )
{
2005-03-23 21:01:41 +03:00
tape_class = class_create ( THIS_MODULE , " tape390 " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void __exit tape_exit ( void )
{
2005-03-23 21:01:41 +03:00
class_destroy ( tape_class ) ;
2005-04-17 02:20:36 +04:00
tape_class = NULL ;
}
postcore_initcall ( tape_init ) ;
module_exit ( tape_exit ) ;