162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* ATM driver model support. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/slab.h> 662306a36Sopenharmony_ci#include <linux/init.h> 762306a36Sopenharmony_ci#include <linux/kobject.h> 862306a36Sopenharmony_ci#include <linux/atmdev.h> 962306a36Sopenharmony_ci#include "common.h" 1062306a36Sopenharmony_ci#include "resources.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define to_atm_dev(cldev) container_of(cldev, struct atm_dev, class_dev) 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic ssize_t type_show(struct device *cdev, 1562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct atm_dev *adev = to_atm_dev(cdev); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s\n", adev->type); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic ssize_t address_show(struct device *cdev, 2362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct atm_dev *adev = to_atm_dev(cdev); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%pM\n", adev->esi); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic ssize_t atmaddress_show(struct device *cdev, 3162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci unsigned long flags; 3462306a36Sopenharmony_ci struct atm_dev *adev = to_atm_dev(cdev); 3562306a36Sopenharmony_ci struct atm_dev_addr *aaddr; 3662306a36Sopenharmony_ci int count = 0; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci spin_lock_irqsave(&adev->lock, flags); 3962306a36Sopenharmony_ci list_for_each_entry(aaddr, &adev->local, entry) { 4062306a36Sopenharmony_ci count += scnprintf(buf + count, PAGE_SIZE - count, 4162306a36Sopenharmony_ci "%1phN.%2phN.%10phN.%6phN.%1phN\n", 4262306a36Sopenharmony_ci &aaddr->addr.sas_addr.prv[0], 4362306a36Sopenharmony_ci &aaddr->addr.sas_addr.prv[1], 4462306a36Sopenharmony_ci &aaddr->addr.sas_addr.prv[3], 4562306a36Sopenharmony_ci &aaddr->addr.sas_addr.prv[13], 4662306a36Sopenharmony_ci &aaddr->addr.sas_addr.prv[19]); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci spin_unlock_irqrestore(&adev->lock, flags); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return count; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic ssize_t atmindex_show(struct device *cdev, 5462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct atm_dev *adev = to_atm_dev(cdev); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", adev->number); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic ssize_t carrier_show(struct device *cdev, 6262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct atm_dev *adev = to_atm_dev(cdev); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", 6762306a36Sopenharmony_ci adev->signal == ATM_PHY_SIG_LOST ? 0 : 1); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic ssize_t link_rate_show(struct device *cdev, 7162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct atm_dev *adev = to_atm_dev(cdev); 7462306a36Sopenharmony_ci int link_rate; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* show the link rate, not the data rate */ 7762306a36Sopenharmony_ci switch (adev->link_rate) { 7862306a36Sopenharmony_ci case ATM_OC3_PCR: 7962306a36Sopenharmony_ci link_rate = 155520000; 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci case ATM_OC12_PCR: 8262306a36Sopenharmony_ci link_rate = 622080000; 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci case ATM_25_PCR: 8562306a36Sopenharmony_ci link_rate = 25600000; 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci default: 8862306a36Sopenharmony_ci link_rate = adev->link_rate * 8 * 53; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", link_rate); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(address); 9462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(atmaddress); 9562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(atmindex); 9662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(carrier); 9762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(type); 9862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(link_rate); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic struct device_attribute *atm_attrs[] = { 10162306a36Sopenharmony_ci &dev_attr_atmaddress, 10262306a36Sopenharmony_ci &dev_attr_address, 10362306a36Sopenharmony_ci &dev_attr_atmindex, 10462306a36Sopenharmony_ci &dev_attr_carrier, 10562306a36Sopenharmony_ci &dev_attr_type, 10662306a36Sopenharmony_ci &dev_attr_link_rate, 10762306a36Sopenharmony_ci NULL 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int atm_uevent(const struct device *cdev, struct kobj_uevent_env *env) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci const struct atm_dev *adev; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (!cdev) 11662306a36Sopenharmony_ci return -ENODEV; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci adev = to_atm_dev(cdev); 11962306a36Sopenharmony_ci if (!adev) 12062306a36Sopenharmony_ci return -ENODEV; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number)) 12362306a36Sopenharmony_ci return -ENOMEM; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void atm_release(struct device *cdev) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct atm_dev *adev = to_atm_dev(cdev); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci kfree(adev); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic struct class atm_class = { 13662306a36Sopenharmony_ci .name = "atm", 13762306a36Sopenharmony_ci .dev_release = atm_release, 13862306a36Sopenharmony_ci .dev_uevent = atm_uevent, 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciint atm_register_sysfs(struct atm_dev *adev, struct device *parent) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct device *cdev = &adev->class_dev; 14462306a36Sopenharmony_ci int i, j, err; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci cdev->class = &atm_class; 14762306a36Sopenharmony_ci cdev->parent = parent; 14862306a36Sopenharmony_ci dev_set_drvdata(cdev, adev); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci dev_set_name(cdev, "%s%d", adev->type, adev->number); 15162306a36Sopenharmony_ci err = device_register(cdev); 15262306a36Sopenharmony_ci if (err < 0) 15362306a36Sopenharmony_ci return err; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci for (i = 0; atm_attrs[i]; i++) { 15662306a36Sopenharmony_ci err = device_create_file(cdev, atm_attrs[i]); 15762306a36Sopenharmony_ci if (err) 15862306a36Sopenharmony_ci goto err_out; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cierr_out: 16462306a36Sopenharmony_ci for (j = 0; j < i; j++) 16562306a36Sopenharmony_ci device_remove_file(cdev, atm_attrs[j]); 16662306a36Sopenharmony_ci device_del(cdev); 16762306a36Sopenharmony_ci return err; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_civoid atm_unregister_sysfs(struct atm_dev *adev) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct device *cdev = &adev->class_dev; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci device_del(cdev); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ciint __init atm_sysfs_init(void) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci return class_register(&atm_class); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_civoid __exit atm_sysfs_exit(void) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci class_unregister(&atm_class); 18562306a36Sopenharmony_ci} 186