2005-04-16 15:20:36 -07:00
/*
* ( C ) Copyright IBM Corp . 2004
2006-02-01 03:06:31 -08:00
* tape_class . c
2005-04-16 15:20:36 -07:00
*
* Tape class device support
*
* Author : Stefan Bader < shbader @ de . ibm . com >
* Based on simple class device code by Greg K - H
*/
2009-12-18 17:43:21 +01:00
# define KMSG_COMPONENT "tape"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2005-04-16 15:20:36 -07:00
# 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 03:06:31 -08:00
" tape_class.c "
2005-04-16 15:20:36 -07:00
) ;
MODULE_LICENSE ( " GPL " ) ;
2005-03-23 10:01:41 -08:00
static struct class * tape_class ;
2005-04-16 15:20:36 -07: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 00:55:37 -08:00
const struct file_operations * fops ,
2005-04-16 15:20:36 -07:00
char * device_name ,
char * mode_name )
{
struct tape_class_device * tcd ;
int rc ;
char * s ;
2006-03-24 03:15:31 -08:00
tcd = kzalloc ( sizeof ( struct tape_class_device ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07: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 ;
2008-07-21 20:03:34 -07:00
tcd - > class_device = device_create ( tape_class , device ,
tcd - > char_device - > dev , NULL ,
" %s " , tcd - > device_name ) ;
2006-08-07 17:00:28 +02:00
rc = IS_ERR ( tcd - > class_device ) ? PTR_ERR ( tcd - > class_device ) : 0 ;
2006-07-18 13:46:58 +02:00
if ( rc )
goto fail_with_cdev ;
rc = sysfs_create_link (
2005-04-16 15:20:36 -07:00
& device - > kobj ,
& tcd - > class_device - > kobj ,
tcd - > mode_name
) ;
2006-07-18 13:46:58 +02:00
if ( rc )
goto fail_with_class_device ;
2005-04-16 15:20:36 -07:00
return tcd ;
2006-07-18 13:46:58 +02:00
fail_with_class_device :
2007-10-22 12:52:42 +02:00
device_destroy ( tape_class , tcd - > char_device - > dev ) ;
2006-07-18 13:46:58 +02:00
2005-04-16 15:20:36 -07:00
fail_with_cdev :
cdev_del ( tcd - > char_device ) ;
fail_with_tcd :
kfree ( tcd ) ;
return ERR_PTR ( rc ) ;
}
EXPORT_SYMBOL ( register_tape_dev ) ;
2008-04-17 07:46:05 +02:00
void unregister_tape_dev ( struct device * device , struct tape_class_device * tcd )
2005-04-16 15:20:36 -07:00
{
if ( tcd ! = NULL & & ! IS_ERR ( tcd ) ) {
2008-04-17 07:46:05 +02:00
sysfs_remove_link ( & device - > kobj , tcd - > mode_name ) ;
2007-10-22 12:52:42 +02:00
device_destroy ( tape_class , tcd - > char_device - > dev ) ;
2005-04-16 15:20:36 -07:00
cdev_del ( tcd - > char_device ) ;
kfree ( tcd ) ;
}
}
EXPORT_SYMBOL ( unregister_tape_dev ) ;
static int __init tape_init ( void )
{
2005-03-23 10:01:41 -08:00
tape_class = class_create ( THIS_MODULE , " tape390 " ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static void __exit tape_exit ( void )
{
2005-03-23 10:01:41 -08:00
class_destroy ( tape_class ) ;
2005-04-16 15:20:36 -07:00
tape_class = NULL ;
}
postcore_initcall ( tape_init ) ;
module_exit ( tape_exit ) ;